Nabil Derbel

191 papers A 2B 1C 3Journal 65Unranked 114
YearRankTypeTitle / Venue / Authors
2025 conf
SSD
Shimaa Janabi, Shaimaa Shukri Abd. Alhalim, Ali F. Hassoon, Zainab Mahmood Abed, Nabil Derbel
2025 conf
SSD
Nourchen Zaghden Dammak, Hala Bezine, Ahmed Saïd Nouri, Nabil Derbel
2025 conf
SSD
Yosra Ben Fadhel, Khawla Kachroudi, Achraf Derbel, Hedi Trabelsi, Nabil Derbel
2025 conf
I2MTC
Cherif Ouni, Nour Ammar, Duoxiao Xing, Ahmed Yahia Kallel, Ahmed Fakhfakh, Nabil Derbel, John Thomas Horstmann, Olfa Kanoun
2025 conf
SSD
Ayoub Trabelsi, Nour Ammar, Cherif Ouni, Ahmed Yahia Kallel, Ahmed Fakhfakh, Salwa Fakhfakh Sahnoun, Nabil Derbel, Olfa Kanoun
2025 conf
SSD
Shaimaa Shukri Abd. Alhalim, Wissem Bahloul, Mohamed Chtourou, Nabil Derbel
2025 conf
SSD
Aicha Znidi, Ahmed Saïd Nouri, Nabil Derbel
2025 J jnl
IEEE Access
Rim Jallouli-Khlif, Fatma Abdelhédi, Chadia Zayane, Ahmed Saïd Nouri, Nabil Derbel
2025 conf
SSD
Rawia Chakroun, Salma Charmi, Nabil Derbel
2024 conf
SSD
Shaimaa Shukri Abd. Alhalim, Wissem Bahloul, Mohamed Chtourou, Nabil Derbel
2024 conf
SSD
Mahra Al-Ali, Mohamed Deriche, Nabil Derbel
2024 conf
SSD
Aicha Znidi, Fatma Abdelhédi, Ahmed Saïd Nouri, Nabil Derbel
2024 J jnl
IEEE Access
Najib Alabsari, Abdul-Wahid A. Saif, Sami El-Ferik, Salih O. Duffuaa, Nabil Derbel
2024 J jnl
IEEE Access
Najib Alabsari, Abdul-Wahid A. Saif, Sami El-Ferik, Salih O. Duffuaa, Nabil Derbel
2024 conf
SSD
Yosra Ben Fadhel, Achraf Derbel, Hatem Garrab, Hedi Trabelsi, Mohamed Deriche, Nabil Derbel
2024 conf
SSD
Jawad Hamad Hameed, Wassan Adnan Hashim, Nabil Derbel, Shahab Wahhab Kareem, Shadan M. J. Abdalwahd
2024 conf
SSD
Mohammad A. Faraj, Nabil Derbel, Boutheina Maalej
2024 J jnl
Expert Syst. Appl.
Mouna Medhioub, Sonda Ammar Bouhamed, Imene Khanfir Kallel, Nabil Derbel, Olfa Kanoun
2024 conf
I2MTC
Nour Ammar, Cherif Ouni, Ahmed Yahia Kallel, Ahmed Fakhfakh, Nabil Derbel, Olfa Kanoun
2024 conf
SSD
Mohamed A. J. Al-Ani, Nabil Derbel
2024 conf
SSD
Marwah Qasim Al-Obaidi, Nabil Derbel, Wassan Adnan Hashim, Hussein Alsheakh
2024 conf
SSD
Achraf Derbel, Carlo Trigona, Noura Baccar, Nabil Derbel
2023 conf
SSD
Rawia Chakroun, Ramzi Ben Ayed, Nabil Derbel
2023 J jnl
Int. J. Bifurc. Chaos
Karama Koubaâ, Nabil Derbel
2023 J jnl
Int. J. Emerg. Technol. Learn.
Marwah Qasim Al-Obaidi, Nabil Derbel
2023 conf
SSD
Yosra Ben Fadhel, Ghada Bouattour, Dhouha Bouchaala, Nabil Derbel, Olfa Kanoun
2023 C conf
CoDIT
Fatma Abdelhédi, Ismail Ben Abdallah, Yassine Bouteraa, Nabil Derbel
2023 conf
SSD
Mohammad A. Faraj, Boutheina Maalej, Nabil Derbel
2023 conf
SSD
Intissar Zaway, Rim Jallouli-Khlif, Boutheina Maalej, Hanène Medhaffar, Nabil Derbel
2023 conf
SSD
Wassan Adnan Hashim, Jawad Hamad Hameed, Nabil Derbel
2023 conf
SSD
Mohamed A. J. Al-Ani, Nabil Derbel
2023 conf
SSD
Mohammad A. Faraj, Boutheina Maalej, Nabil Derbel
2023 B conf
ICCCI
Mouna Medhioub, Sonda Ammar Bouhamed, Imen Khanfir Kallel, Nabil Derbel, Olfa Kanoun
2022 J jnl
Sensors
Bilel Ben Atitallah, Ahmed Yahia Kallel, Dhouha Bouchaala, Nabil Derbel, Olfa Kanoun
2022 J jnl
Concurr. Comput. Pract. Exp.
Nesrine Keskes, Sameh Fakhfakh, Olfa Kanoun, Nabil Derbel
2022 conf
SSD
Mohammad A. Faraj, Boutheina Maalej, Nabil Derbel, Mohamed Deriche
2022 conf
SSD
Sameh Mahjoub, Larbi Chrifi-Alaoui, Bruno Marhic, Laurent Delahoche, Jean-Baptiste Masson, Nabil Derbel
2022 J jnl
Biomed. Signal Process. Control.
Nesrine Keskes, Sameh Fakhfakh, Olfa Kanoun, Nabil Derbel
2021 conf
SSD
Bilel Ben Atitallah, Jose Roberto Bautista-Quijano, Haythem Ayari, Ahmed Yahia Kallel, Dhouha Bouchaala, Nabil Derbel, Olfa Kanoun
2021 conf
ICSC
Rim Jallouli-Khlif, Boutheina Maalej, Pierre Melchior, Nabil Derbel
2021 conf
SSD
Khalissa Behih, Khier Benmahammed, Djamila Zehar, Aida Cherif, Nabil Derbel
2021 conf
SSD
Yosra Ben Fadhel, Ghada Bouattour, Dhouha Bouchaala, Nabil Derbel, Olfa Kanoun
2021 conf
SSD
Chiraz Naggara, Dhouha Bouchaala, Rajarajan Ramalingame, Nabil Derbel, Olfa Kanoun
2021 conf
SSD
Intissar Zaway, Rim Jallouli-Khlif, Boutheina Maalej, Hanène Medhaffar, Nabil Derbel
2021 conf
SSD
Marwah Qasim Al-Obaidi, Nabil Derbel, Wasan A. Hashim, Karim M. Aljebory
2021 J jnl
Int. J. Autom. Control.
Yosra Miladi, Nabil Derbel, Moez Feki
2021 conf
SSD
Abdallah Adawy, Ghada Bouattour, Mohammed Ibbini, Nabil Derbel, Olfa Kanoun
2020 conf
SSD
Boutheina Maalej, Hanène Medhaffar, Ahmed Chemori, Nabil Derbel
2020 J jnl
Int. J. Autom. Control.
Hanène Medhaffar, Moez Feki, Nabil Derbel
2020 conf
SSD
Yosra Ben Fadhel, Ghada Bouattour, Dhouha Bouchaala, Salem Rahmani, Olfa Kanoun, Nabil Derbel
2020 conf
SSD
Nesrine Boujelben, Mohamed Djemel, Nabil Derbel
2020 conf
SSD
Rawia Chakroun, Ramzi Ben Ayed, Nabil Derbel
2020 conf
SSD
Sameh El Mahjoub, Marwa Ayadi, Ferdaws Masmoudi Loukil, Nabil Derbel
2020 J jnl
Int. J. Comput. Appl. Technol.
Asma Aribi, Najah Yousfi-Allagui, Nabil Derbel
2020 conf
SSD
Marwah Qasim Al-Obaidi, Twana Ghany Hamid, Nabil Derbel
2020 conf
SSD
Bilel Ben Atitallah, Rim Barioul, Amani Ghribi, Dhouha Bouchaala, Nabil Derbel, Olfa Kanoun
2020 ch.
New Trends in Robot Control
Racem Jribi, Boutheina Maalej, Nabil Derbel
2020 conf
SSD
Ahmed Yahia Kallel, Dhouha Bouchaala, Yesmine Ben Elhaj, Thomas Günther, Olfa Kanoun, Nabil Derbel
2020 ch.
New Trends in Robot Control
Boutheina Maalej, Ahmed Chemori, Nabil Derbel
2020 book
Jawhar Ghommam, Nabil Derbel, Quanmin Zhu
2020 conf
SSD
Omar Naifar, Assaad Jmal, Nabil Derbel
2020 conf
SSD
A. Gharbi, Ahmed Yahia Kallel, Ayda Bouhamed, Ammar Al-Hamry, Olfa Kanoun, Nabil Derbel
2020 conf
SSD
Mouna Medhioub, Sonda Ammar Bouhamed, Imen Khanfir Kallel, Nabil Derbel, Olfa Kanoun
2020 J jnl
IEEE Access
Amal Charfi, Sonda Ammar Bouhamed, Éloi Bossé, Imene Khanfir Kallel, Wassim Bouchaala, Basel Solaiman, Nabil Derbel
2020 conf
IEEE SENSORS
Bilel Ben Atitallah, Muhammed Bilal Abbasi, Rim Barioul, Dhouha Bouchaala, Nabil Derbel, Olfa Kanoun
2020 ch.
New Trends in Robot Control
Djamila Zehar, Aida Chérif, Khalissa Behih, Khier Benmahammed, Nabil Derbel
2020 ch.
New Trends in Robot Control
Mohamed Allagui, Najah Yousfi, Nabil Derbel, Pierre Melchior
2019 J jnl
Int. J. Comput. Appl. Technol.
Najah Yousfi-Allagui, Nabil Derbel, Pierre Melchior
2019 conf
SSD
Najah Yousfi-Allagui, Donia Ben Halima Abid, Nabil Derbel
2019 J jnl
J. Autom. Mob. Robotics Intell. Syst.
Lobna Amouri, Mohamed Jallouli, Cyril Novales, Gérard Poisson, Nabil Derbel
2019 conf
SSD
Ilef Ketata, Sadok Bdiri, Nabil Derbel, Faouzi Derbel
2019 J jnl
Int. J. Model. Identif. Control.
Marwa Ayadi, Omar Naifar, Nabil Derbel
2019 conf
SSD
Boutheina Maalej, Ahmed Chemori, Nabil Derbel
2019 conf
SSD
Rabeb Abid, Sameh Mahjoub, Ferdaous Masmoudi, Nabil Derbel
2019 J jnl
Int. J. Comput. Appl. Technol.
Faten Cherni, Chokri Rekik, Nabil Derbel
2019 conf
SSD
Bilel Ben Atitallah, Rajarajan Ramalingame, Nabil Derbel, Olfa Kanoun
2019 J jnl
Int. J. Model. Identif. Control.
Fatma Abdelhédi, Nabil Derbel
2019 conf
SSD
Racem Jribi, Boutheina Maalej, Nabil Derbel
2019 J jnl
Int. J. Intell. Comput. Cybern.
Hanène Medhaffar, Moez Feki, Nabil Derbel
2019 conf
SSD
Rim Jallouli-Khlif, Ahmed Abid, Pierre Melchior, Nabil Derbel
2018 conf
SSD
Mahdi Guermazi, Nabil Derbel, Olfa Kanoun
2018 conf
SSD
Sameh Mahjoub, Marwa Ayadi, Ferdaws Masmoudi, Nabil Derbel
2018 J jnl
Int. J. Model. Identif. Control.
Yassine Bouteraa, Nabil Derbel
2018 conf
SSD
Assaad Jmal, Omar Naifar, Abdellatif Ben Makhlouf, Nabil Derbel
2018 conf
SSD
Najah Yousfi-Allagui, Donia Ben Halima Abid, Nabil Derbel
2018 J jnl
Circuits Syst. Signal Process.
Zouhour Ben Ahmed, Nabil Derbel
2018 conf
SSD
Boutheina Maalej, Racem Jribi, Noura Ayadi, Fatma Abdelhédi, Nabil Derbel
2018 conf
SSD
Noura Ayadi, Boutheina Maalej, Nabil Derbel
2018 conf
SSD
Najah Yousfi, Mohamed Allagui, Pierre Melchior, Nabil Derbel
2018 conf
SSD
Nesrine Keskes, Sameh Fakhfakh Ghribi, Rim Barioul, Nabil Derbel
2018 conf
SSD
Malek Guizani, Rabeb Abid, Ferdaous Masmoudi, Mohamed Djemel, Nabil Derbel
2018 J jnl
IEEE Instrum. Meas. Mag.
Mahdi Guermazi, Ahmed Fendri, Olfa Kanoun, Nabil Derbel
2018 conf
SSD
Mohamed Allagui, Najah Yousfi, Nabil Derbel, Pierre Melchior
2018 conf
SSD
Assaad Jmal, Omar Naifar, Nabil Derbel
2018 conf
SSD
Nadia Smaoui, Nabil Derbel
2018 J jnl
J. Artif. Intell. Soft Comput. Res.
Noura Ayadi, Nabil Derbel, Nicolas Morette, Cyril Novales, Gérard Poisson
2018 conf
SSD
Mabrouka Zemzemi, Nesrine Keskes, Rim Barioul, Sameh Fakhfakh, Imene Khanfir Kallel, Nabil Derbel, Olfa Kanoun
2017 J jnl
Int. J. Model. Identif. Control.
Maïssa Boujelben, Chokri Rekik, Nabil Derbel
2017 J jnl
Int. J. Model. Identif. Control.
Fatma Abdelhédi, Nabil Derbel
2017 conf
SDD
Hasna Dhehibi, Ahmed Zouinkhi, Olfa Kanoun, Nabil Derbel
2017 conf
I2MTC
Manel Zouari, Slim Naifar, Martin Götz, Nabil Derbel, Olfa Kanoun
2017 J jnl
Int. J. Autom. Control.
Faten Cherni, Maïssa Boujelben, Lotfi Jaiem, Yassine Bouteraa, Chokri Rekik, Nabil Derbel
2017 conf
SDD
Rabeb Abid, Ferdaous Masmoudi, Nabil Derbel
2017 conf
SDD
Nesrine Boujelben, Ferdaous Masmoudi, Mohamed Djemel, Nabil Derbel
2017 conf
SDD
Maïssa Boujelben, Dorra Ayedi, Chokri Rekik, Nabil Derbel
2017 J jnl
Int. J. Comput. Appl. Technol.
Noura Ayadi, Manel Turki, Rania Ghribi, Nabil Derbel
2017 conf
SDD
Zouhour Ben Ahmed, Nabil Derbel
2017 ch.
Applications of Sliding Mode Control
Marwa Fathallah, Fatma Abdelhédi, Nabil Derbel
2017 J jnl
Int. J. Model. Identif. Control.
Najah Yousfi-Allagui, Nabil Derbel, Pierre Melchior
2017 conf
SDD
Marwa Ayadi, Omar Naifar, Nabil Derbel
2017 conf
SDD
Jihen Loukil, Ferdaous Masmoudi, Nabil Derbel
2017 conf
SDD
Assaad Jmal, Omar Naifar, Nabil Derbel
2016 J jnl
Int. J. Model. Identif. Control.
Maïssa Boujelben, Chokri Rekik, Nabil Derbel
2016 conf
SSD
Marwa Fathallah, Fatma Abdelhédi, Nabil Derbel
2016 conf
SSD
Fatma Abdelhedi Bouaziz, Yassine Bouteraa, Nabil Derbel
2016 J jnl
Appl. Soft Comput.
Mohamed Slim Masmoudi, Najla Krichen Masmoudi, Mohamed Masmoudi, Nabil Derbel
2016 conf
SSD
Fatma Ben Salem, Nabil Derbel
2016 conf
SSD
Jihen Loukil, Ferdaous Masmoudi, Nabil Derbel
2016 J jnl
Int. J. Circuit Theory Appl.
Yosra Miladi, Moez Feki, Nabil Derbel
2016 J jnl
Int. J. Comput. Appl. Technol.
Chokri Rekik, Mohamed Jallouli, Nabil Derbel
2016 conf
SSD
Ahmed Abid, Rim Jallouli-Khlif, Pierre Melchior, Nabil Derbel
2016 conf
SSD
Marwa Ayadi, Fatma Ben Salem, Nabil Derbel
2016 conf
SSD
Ferdaous Masmoudi, Fatma Ben Salem, Nabil Derbel
2016 conf
SSD
Ahmed Abid, Rim Jallouli-Khlif, Nabil Derbel, Pierre Melchior
2015 J jnl
Int. J. Robotics Autom.
Maïssa Boujelben, Chokri Rekik, Nabil Derbel
2015 conf
SSD
Faten Cherni, Yassine Bouteraa, Chokri Rekik, Nabil Derbel
2015 conf
SSD
Ghada Bouattour, Bilel Kallel, Koushik Sasmal, Olfa Kanoun, Nabil Derbel
2015 conf
SSD
Manel Taktak-Meziou, Jawhar Ghommam, Nabil Derbel
2015 conf
SSD
Aicha Daoud, Fatma Ben Salem, Nabil Derbel
2015 J jnl
Int. J. Autom. Comput.
Sonia Mahjoub, Faïçal Mnif, Nabil Derbel
2015 J jnl
Int. J. Model. Identif. Control.
Emna Kolsi Gdoura, Moez Feki, Nabil Derbel
2015 J jnl
Commun. Nonlinear Sci. Numer. Simul.
Yosra Miladi, Moez Feki, Nabil Derbel
2015 conf
I2MTC
Dhouha Bouchaala, Emna Mekki, Thomas Günther, Paul Büschel, Olfa Kanoun, Nabil Derbel
2015 conf
SSD
Zouhour Ben Ahmed, Gérard Favier, Nabil Derbel
2014 C conf
CCA
Manel Taktak-Meziou, Ahmed Chemori, Jawhar Ghommam, Nabil Derbel
2014 conf
SSD
Imen Maalej, Donia Ben Halima Abid, Chokri Rekik, Nabil Derbel
2014 conf
ISIE
Imen Maalej, Chokri Rekik, Donia Ben Halima Abid, Nabil Derbel
2014 conf
SSD
Emna Kolsi Gdoura, Moez Feki, Nabil Derbel
2014 conf
SSD
Manel Taktak-Meziou, Ahmed Chemori, Jawhar Ghommam, Nabil Derbel
2014 conf
SSD
Fatma Ben Salem, Nabil Derbel
2013 conf
SSD
Dhouha Bouchaala, Qinghai Shi, Xinyue Chen, Olfa Kanoun, Nabil Derbel
2013 conf
SSD
Maïssa Boujelben, Chokri Rekik, Nabil Derbel
2013 conf
SSD
Najah Yousfi, Pierre Melchior, Rim Jallouli-Khlif, Patrick Lanusse, Nabil Derbel, Alain Oustaloup
2013 conf
MED
Manel Taktak-Meziou, Ahmed Chemori, Jawhar Ghommam, Nabil Derbel
2013 conf
ALCOSP
Adel Mahjoub, Fouad Giri, Fatima-Zahra Chaoui, Nabil Derbel
2013 conf
SSD
Sonia Mahjoub, Faïçal Mnif, Nabil Derbel
2013 conf
SSD
Emna Kolsi Gdoura, Moez Feki, Nabil Derbel
2013 conf
SSD
Zouhour Ben Ahmed, Gérard Favier, Nabil Derbel
2013 A conf
IROS
Manel Taktak-Meziou, Ahmed Chemori, Jawhar Ghommam, Nabil Derbel
2012 conf
SSD
Lobna Amouri, Cyril Novales, Mohamed Jallouli, Gérard Poisson, Nabil Derbel
2012 conf
SSD
Dhouha Bouchaala, Qinghai Shi, Xinyue Chen, Olfa Kanoun, Nabil Derbel
2012 conf
SSD
Haifa Souilem, Hassen Mekki, Nabil Derbel
2012 conf
SSD
Nidhal Ben Amor, Olfa Kanoun, Nabil Derbel
2012 conf
SSD
Yosra Miladi, Moez Feki, Nabil Derbel
2012 J jnl
Int. J. Model. Identif. Control.
Rim Jallouli-Khlif, Pierre Melchior, Nabil Derbel, Alain Oustaloup
2012 conf
SSD
Manel Taktak-Meziou, Jawhar Ghommam, Nabil Derbel
2011 J jnl
Int. J. Bifurc. Chaos
Rafika Hamza, Moez Feki, Nabil Derbel, B. G. M. Robert, Abdelali El Aroudi
2011 J jnl
J. Robotics
Yassine Bouteraa, Jawhar Ghommam, Gérard Poisson, Nabil Derbel
2011 J jnl
Int. J. Comput. Appl. Technol.
Najla Krichen Masmoudi, Chokri Rekik, Mohamed Djemel, Nabil Derbel
2011 J jnl
J. Comput.
Sonia Mahjoub, Faïçal Mnif, Nabil Derbel
2011 J jnl
Appl. Soft Comput.
Raouf Ketata, Yassine Rezgui, Nabil Derbel
2011 J jnl
Appl. Soft Comput.
Najla Krichen Masmoudi, Chokri Rekik, Mohamed Djemel, Nabil Derbel
2010 J jnl
Int. J. Intell. Syst. Technol. Appl.
Emna Zouari, Hanène Medhaffar, Nabil Derbel
2010 J jnl
Int. J. Intell. Comput. Cybern.
Slim Frikha, Mohamed Djemel, Nabil Derbel
2010 J jnl
Int. J. Model. Identif. Control.
Mohamed Jallouli, Chokri Rekik, Mohamed Chtourou, Nabil Derbel
2008 J jnl
Int. J. Robotics Autom.
Chokri Rekik, Mohamed Djemel, Nabil Derbel
2008 J jnl
Int. J. Model. Identif. Control.
Hiyem Frikha-Djemel, Nabil Derbel
2008 conf
ICINCO-SPSMC
Rostom Kachouri, Khalifa Djemal, Hichem Maaref, Dorra Sellami Masmoudi, Nabil Derbel
2008 J jnl
J. Adv. Comput. Intell. Intell. Informatics
Mohamed Slim Masmoudi, Willie Tsui, Insop Song, Fakhreddine Karray, Mohamed Masmoudi, Nabil Derbel
2008 J jnl
Int. J. Model. Identif. Control.
Aida Fourati, Moez Feki, Nabil Derbel
2007 J jnl
Int. J. Model. Identif. Control.
Hassen Mekki, Mohamed Chtourou, Nabil Derbel
2007 J jnl
Int. J. Model. Identif. Control.
Jawhar Ghommam, Faïçal Mnif, Abderraouf Benali, Nabil Derbel
2007 J jnl
Int. J. Model. Identif. Control.
Chokri Rekik, Mohamed Djemel, Nabil Derbel
2006 J jnl
Int. J. Model. Identif. Control.
Hanène Medhaffar, Nabil Derbel, Tarak Damak
2006 J jnl
IEEE Trans. Control. Syst. Technol.
Jawhar Ghommam, Faïçal Mnif, Abderraouf Benali, Nabil Derbel
2006 J jnl
Int. J. Robotics Autom.
Nabil Derbel, Adel M. Alimi
2006 J jnl
Simul. Model. Pract. Theory
Hassen Mekki, Mohamed Chtourou, Nabil Derbel
2005 conf
SITIS
Amin Kallel, Dorra Sellami Masmoudi, Mounir Salhi, Med Amine Ben Aïcha, Imene Khanfir Kallel, Nabil Derbel
2005 J jnl
Int. J. Comput. Intell. Appl.
Hanène Medhaffar, Tarak Damak, Nabil Derbel
2005 J jnl
Adv. Eng. Softw.
Nabil Derbel, Mohamed Abid
2005 J jnl
Control. Intell. Syst.
Hassen Mekki, Mohamed Chtourou, Nabil Derbel
2003 A conf
ICDAR
Hala Bezine, Adel M. Alimi, Nabil Derbel
2003 C conf
CCA
Chokri Rekik, Mohamed Djemel, Nabil Derbel
2002 conf
ISIC
Chokri Rekik, Mohamed Djemel, Nabil Derbel, Adel M. Alimi
2002 conf
ISIC
Amel Ouezri, Nabil Derbel
2001 J jnl
Integr. Comput. Aided Eng.
Adel M. Alimi, Nabil Derbel
2001 J jnl
Comput. Electr. Eng.
Nabil Derbel
1999 conf
ECC
Nabil Derbel, Adel M. Alimi
1998 J jnl
Int. J. Syst. Sci.
Nabil Derbel, Mohamed Chtourou, Ahmed Masmoudi
1996 J jnl
Int. J. Syst. Sci.
Mohamed Chtourou, Nabil Derbel, Mohamed Ben Ali Kamoun
1994 J jnl
IEEE Trans. Autom. Control.
Nabil Derbel, Mohamed Ben Ali Kamoun, Michel Poloujadoff
tests/integration/test_hashes.py
← Index tests/integration/test_hashes.py python
"""
Integration tests for the HashExtractor class.
"""
import pytest
import hashlib
from unittest.mock import Mock, patch, MagicMock

pytestmark = [pytest.mark.integration]


class TestHashExtractorInitialization:
    """Tests for HashExtractor initialization."""

    def test_initialization_elf(self, elf_binary_path, mock_logger):
        """Test initialization with ELF file."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            assert extractor.filepath == elf_binary_path
            assert extractor.hashes is None
            assert extractor.filetype == "elf"
            assert extractor.macho is None

    def test_initialization_with_macho_object(self, elf_binary_path, mock_logger):
        """Test initialization with pre-parsed macho object."""
        from redb.extractors.hashes import HashExtractor

        mock_macho = MagicMock()
        mock_macho.get_architectures.return_value = ["x86_64"]

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger, macho=mock_macho)

            assert extractor.macho is mock_macho

    def test_initialization_pe(self, pe_binary_path, mock_logger):
        """Test initialization with PE file."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(pe_binary_path, mock_logger)

            assert extractor.filepath == pe_binary_path
            assert extractor.filetype == "pebin"
            # PE object should be created
            assert extractor.pe is not None

    def test_elastic_index_suffix(self, elf_binary_path, mock_logger):
        """Test that elastic_index has correct suffix."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            assert "-hashes" in extractor.elastic_index


class TestHashExtractorTag:
    """Tests for tag method."""

    def test_tag_value(self, elf_binary_path, mock_logger):
        """Test that tag returns correct value."""
        from redb.extractors.hashes import HashExtractor
        from redb.extractors.enum import Tag

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            assert extractor.tag() == Tag.HASH.value
            assert extractor.tag() == "hash"


class TestHashExtractorBasicHashes:
    """Tests for basic hash extraction."""

    def test_extract_md5(self, elf_binary_path, mock_logger, known_hashes):
        """Test MD5 hash extraction."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            assert result.md5 == known_hashes['md5']

    def test_extract_sha1(self, elf_binary_path, mock_logger, known_hashes):
        """Test SHA1 hash extraction."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            assert result.sha1 == known_hashes['sha1']

    def test_extract_sha256(self, elf_binary_path, mock_logger, known_hashes):
        """Test SHA256 hash extraction."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            assert result.sha256 == known_hashes['sha256']

    def test_extract_ssdeep(self, elf_binary_path, mock_logger):
        """Test ssdeep hash extraction."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # ssdeep should be a string
            assert isinstance(result.ssdeep_hash, str)

    def test_extract_tlsh(self, elf_binary_path, mock_logger):
        """Test TLSH hash extraction."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # TLSH should be a string
            assert isinstance(result.tlsh_hash, str)


class TestHashExtractorPEHashes:
    """Tests for PE-specific hash extraction."""

    def test_extract_imphash(self, pe_binary_path, mock_logger):
        """Test imphash extraction for PE file."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(pe_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # Imphash should be set for PE files
            if extractor.pe is not None:
                assert result.imphash is not None or result.imphash is None  # May or may not have imports

    def test_extract_authentihash(self, pe_binary_path, mock_logger):
        """Test authentihash extraction for PE file."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(pe_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # Authentihash should be set for PE files
            if extractor.pe is not None:
                assert result.authentihash is not None

    def test_pe_hashes_not_set_for_elf(self, elf_binary_path, mock_logger):
        """Test that PE-specific hashes are not set for ELF files."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # PE-specific hashes should be None for ELF
            assert result.imphash is None
            assert result.authentihash is None
            assert result.richhash is None


class TestHashExtractorRichHeaderHashes:
    """Tests for Rich header hash extraction."""

    def test_compute_richhash(self, pe_binary_path, mock_logger):
        """Test Rich header hash computation."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(pe_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # Rich hash may or may not be present depending on the PE
            if result.richhash is not None:
                assert isinstance(result.richhash, str)
                assert len(result.richhash) == 32  # MD5 hex length

    def test_compute_richpe_hash(self, pe_binary_path, mock_logger):
        """Test RichPE hash computation."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(pe_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # RichPE hash may or may not be present
            if result.richpe_hash is not None:
                assert isinstance(result.richpe_hash, str)
                assert len(result.richpe_hash) == 32  # MD5 hex length

    def test_compute_richpv_hash(self, pe_binary_path, mock_logger):
        """Test RichPV hash computation."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(pe_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # RichPV hashes may or may not be present
            if result.richpv_hash is not None:
                assert isinstance(result.richpv_hash, str)
            if result.richpv_hash_sorted is not None:
                assert isinstance(result.richpv_hash_sorted, str)


class TestHashExtractorELFHashes:
    """Tests for ELF-specific hash extraction."""

    def test_extract_elf_import_hash(self, elf_binary_path, mock_logger):
        """Test ELF import hash extraction."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # Import hash may or may not be present
            if result.import_hash is not None:
                assert isinstance(result.import_hash, str)
                assert len(result.import_hash) == 32

    def test_extract_elf_export_hash(self, elf_binary_path, mock_logger):
        """Test ELF export hash extraction."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # Export hash may or may not be present
            if result.export_hash is not None:
                assert isinstance(result.export_hash, str)

    def test_extract_elf_section_hash(self, elf_binary_path, mock_logger):
        """Test ELF section hash extraction."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # Section hash should be present for valid ELF
            if result.section_hash is not None:
                assert isinstance(result.section_hash, str)

    def test_extract_elf_symbol_hash(self, elf_binary_path, mock_logger):
        """Test ELF symbol hash extraction."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # Symbol hash (symhash) may or may not be present
            if result.symbol_hash is not None:
                assert isinstance(result.symbol_hash, str)

    def test_extract_elf_dynamic_hash(self, elf_binary_path, mock_logger):
        """Test ELF dynamic hash extraction."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # Dynamic hash may or may not be present
            if result.dynamic_hash is not None:
                assert isinstance(result.dynamic_hash, str)


class TestHashExtractorPrepareExportData:
    """Tests for prepare_export_data method."""

    def test_prepare_export_elasticsearch(self, elf_binary_path, mock_logger):
        """Test prepare_export_data for Elasticsearch."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)
            extractor.extract()

            result = extractor.prepare_export_data("ElasticsearchExporter")

            assert result is extractor.hashes

    def test_prepare_export_clickhouse(self, elf_binary_path, mock_logger):
        """Test prepare_export_data for ClickHouse."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)
            extractor.extract()

            result = extractor.prepare_export_data("ClickHouseExporter")

            # Should return tuple of (data, column_names, column_type_names)
            assert isinstance(result, tuple)
            assert len(result) == 3

            data, column_names, column_type_names = result

            assert isinstance(data, list)
            assert isinstance(column_names, list)
            assert isinstance(column_type_names, list)

            # Check expected columns
            assert 'sha256' in column_names
            assert 'md5' in column_names
            assert 'sha1' in column_names
            assert 'ssdeep_hash' in column_names
            assert 'tlsh_hash' in column_names

    def test_prepare_export_clickhouse_pe(self, pe_binary_path, mock_logger):
        """Test prepare_export_data for ClickHouse with PE file."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(pe_binary_path, mock_logger)
            extractor.extract()

            result = extractor.prepare_export_data("ClickHouseExporter")

            data, column_names, column_type_names = result

            # PE-specific columns should be present
            assert 'authentihash' in column_names
            assert 'imphash' in column_names
            assert 'richhash' in column_names

    def test_prepare_export_clickhouse_has_macho_columns(self, elf_binary_path, mock_logger):
        """Test prepare_export_data for ClickHouse includes Mach-O hash columns."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)
            extractor.extract()

            result = extractor.prepare_export_data("ClickHouseExporter")

            data, column_names, column_type_names = result

            # Mach-O hash columns should be present
            assert 'macho_dylib_hash' in column_names
            assert 'macho_import_hash' in column_names
            assert 'macho_export_hash' in column_names
            assert 'macho_entitlement_hash' in column_names
            assert 'macho_symhash' in column_names


class TestHashExtractorClickHouseTable:
    """Tests for get_clickhouse_table method."""

    def test_clickhouse_table_name(self, elf_binary_path, mock_logger):
        """Test correct ClickHouse table name."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            assert extractor.get_clickhouse_table() == "redb_hashes"


@pytest.mark.unit
@pytest.mark.dataclass
class TestHashExtractorHashesDataclass:
    """Tests for Hashes dataclass structure."""

    def test_hashes_dataclass_structure(self, elf_binary_path, mock_logger):
        """Test that Hashes dataclass has expected structure."""
        from redb.extractors.hashes import HashExtractor
        from redb.models.dataclasses import Hashes

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert isinstance(result, Hashes)
            # Required fields
            assert hasattr(result, 'md5')
            assert hasattr(result, 'sha1')
            assert hasattr(result, 'sha256')
            assert hasattr(result, 'ssdeep_hash')
            assert hasattr(result, 'tlsh_hash')
            # Optional fields
            assert hasattr(result, 'authentihash')
            assert hasattr(result, 'imphash')
            assert hasattr(result, 'richhash')

    def test_hashes_dataclass_has_macho_fields(self):
        """Test that Hashes dataclass has Mach-O hash fields."""
        from redb.models.dataclasses import Hashes

        # Create instance with default values
        hashes = Hashes(
            md5="d41d8cd98f00b204e9800998ecf8427e",
            sha1="da39a3ee5e6b4b0d3255bfef95601890afd80709",
            sha256="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
            ssdeep_hash="",
            tlsh_hash=""
        )

        # Verify Mach-O hash fields exist and default to None
        assert hasattr(hashes, 'macho_dylib_hash')
        assert hasattr(hashes, 'macho_import_hash')
        assert hasattr(hashes, 'macho_export_hash')
        assert hasattr(hashes, 'macho_entitlement_hash')
        assert hasattr(hashes, 'macho_symhash')

        assert hashes.macho_dylib_hash is None
        assert hashes.macho_import_hash is None
        assert hashes.macho_export_hash is None
        assert hashes.macho_entitlement_hash is None
        assert hashes.macho_symhash is None

    def test_hashes_dataclass_with_macho_values(self):
        """Test that Hashes dataclass can be created with Mach-O hash values."""
        from redb.models.dataclasses import Hashes

        hashes = Hashes(
            md5="d41d8cd98f00b204e9800998ecf8427e",
            sha1="da39a3ee5e6b4b0d3255bfef95601890afd80709",
            sha256="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
            ssdeep_hash="",
            tlsh_hash="",
            macho_dylib_hash="abc123def456789012345678901234567",
            macho_import_hash="def456abc123789012345678901234567",
            macho_export_hash="789012abc123def456345678901234567",
            macho_entitlement_hash="345678abc123def456789012901234567",
            macho_symhash="901234abc123def456789012345678567"
        )

        assert hashes.macho_dylib_hash == "abc123def456789012345678901234567"
        assert hashes.macho_import_hash == "def456abc123789012345678901234567"
        assert hashes.macho_export_hash == "789012abc123def456345678901234567"
        assert hashes.macho_entitlement_hash == "345678abc123def456789012901234567"
        assert hashes.macho_symhash == "901234abc123def456789012345678567"


class TestHashExtractorErrorHandling:
    """Tests for error handling in HashExtractor."""

    def test_extract_handles_hash_errors(self, elf_binary_path, mock_logger):
        """Test that extract handles hash computation errors gracefully."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            # Even if some hashes fail, we should get a result
            result = extractor.extract()

            assert result is not None

    def test_extract_with_invalid_pe(self, elf_binary_path, mock_logger):
        """Test extraction when PE parsing fails."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            # Force filetype to be 'pebin' but use ELF file
            with patch.object(HashExtractor, '__init__', lambda self, *args, **kwargs: None):
                extractor = HashExtractor.__new__(HashExtractor)
                extractor.filepath = elf_binary_path
                extractor.log = mock_logger
                extractor.hashes = None
                extractor.pe = None
                extractor.filetype = 'pebin'

                with open(elf_binary_path, 'rb') as f:
                    extractor.binary = f.read()

                # Should not crash
                result = extractor._extract_hashes()
                assert result is not None


class TestHashExtractorMachoHashes:
    """Tests for Mach-O specific hash extraction."""

    def test_macho_hashes_not_set_for_elf(self, elf_binary_path, mock_logger):
        """Test that Mach-O hashes are not set for ELF files."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            assert result.macho_dylib_hash is None
            assert result.macho_import_hash is None
            assert result.macho_export_hash is None
            assert result.macho_entitlement_hash is None
            assert result.macho_symhash is None

    def test_macho_hashes_not_set_for_pe(self, pe_binary_path, mock_logger):
        """Test that Mach-O hashes are not set for PE files."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(pe_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            assert result.macho_dylib_hash is None
            assert result.macho_import_hash is None
            assert result.macho_export_hash is None
            assert result.macho_entitlement_hash is None
            assert result.macho_symhash is None

    def test_extract_macho_hashes_with_mock(self, elf_binary_path, mock_logger):
        """Test Mach-O hash extraction with mocked macho object."""
        from redb.extractors.hashes import HashExtractor

        # Create mock macho object
        mock_macho = MagicMock()
        mock_macho.get_architectures.return_value = ["x86_64"]
        mock_macho.get_similarity_hashes.return_value = {
            'dylib_hash': 'abc123def456789012345678901234ab',
            'import_hash': 'def456abc789012345678901234567cd',
            'export_hash': '789012abc456def345678901234567ef',
            'entitlement_hash': '345678abc123def789012901234567gh',
            'symhash': '901234abc123def456789012345678ij'
        }

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger, macho=mock_macho)
            # Override filetype to trigger macho hash extraction
            extractor.filetype = 'macho'

            result = extractor.extract()

            assert result is not None
            assert result.macho_dylib_hash == 'abc123def456789012345678901234ab'
            assert result.macho_import_hash == 'def456abc789012345678901234567cd'
            assert result.macho_export_hash == '789012abc456def345678901234567ef'
            assert result.macho_entitlement_hash == '345678abc123def789012901234567gh'
            assert result.macho_symhash == '901234abc123def456789012345678ij'

    def test_extract_macho_hashes_fat_binary_mock(self, elf_binary_path, mock_logger):
        """Test Mach-O hash extraction for FAT binary with mocked macho object."""
        from redb.extractors.hashes import HashExtractor

        # Create mock macho object for FAT binary
        mock_macho = MagicMock()
        mock_macho.get_architectures.return_value = ["x86_64", "arm64"]  # Multiple archs = FAT
        mock_macho.get_similarity_hashes.return_value = {
            'fat': {
                'dylib_hash': 'fat_dylib_hash_12345678901234567',
                'import_hash': 'fat_import_hash_12345678901234567',
            },
            'combined': {
                'dylib_hash': 'combined_dylib_hash_1234567890123',
            }
        }

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger, macho=mock_macho)
            extractor.filetype = 'macho'

            result = extractor.extract()

            assert result is not None
            # Should use 'fat' key for FAT binaries
            assert result.macho_dylib_hash == 'fat_dylib_hash_12345678901234567'
            assert result.macho_import_hash == 'fat_import_hash_12345678901234567'

    def test_extract_macho_hashes_handles_empty(self, elf_binary_path, mock_logger):
        """Test Mach-O hash extraction handles empty hash dict."""
        from redb.extractors.hashes import HashExtractor

        mock_macho = MagicMock()
        mock_macho.get_architectures.return_value = ["x86_64"]
        mock_macho.get_similarity_hashes.return_value = {}

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger, macho=mock_macho)
            extractor.filetype = 'macho'

            result = extractor.extract()

            # Should not crash, hashes should be None
            assert result is not None
            assert result.macho_dylib_hash is None

    def test_extract_macho_hashes_handles_none(self, elf_binary_path, mock_logger):
        """Test Mach-O hash extraction handles None return."""
        from redb.extractors.hashes import HashExtractor

        mock_macho = MagicMock()
        mock_macho.get_architectures.return_value = ["x86_64"]
        mock_macho.get_similarity_hashes.return_value = None

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger, macho=mock_macho)
            extractor.filetype = 'macho'

            result = extractor.extract()

            # Should not crash
            assert result is not None


class TestHashExtractorConsistency:
    """Tests for hash consistency."""

    def test_hash_consistency_across_extractions(self, elf_binary_path, mock_logger):
        """Test that hashes are consistent across multiple extractions."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor1 = HashExtractor(elf_binary_path, mock_logger)
            result1 = extractor1.extract()

            extractor2 = HashExtractor(elf_binary_path, mock_logger)
            result2 = extractor2.extract()

            assert result1.md5 == result2.md5
            assert result1.sha1 == result2.sha1
            assert result1.sha256 == result2.sha256

    def test_hash_values_are_lowercase(self, elf_binary_path, mock_logger):
        """Test that hash values are lowercase hex strings."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result.md5 == result.md5.lower()
            assert result.sha1 == result.sha1.lower()
            assert result.sha256 == result.sha256.lower()

    def test_hash_lengths_correct(self, elf_binary_path, mock_logger):
        """Test that hash lengths are correct."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert len(result.md5) == 32  # MD5 = 128 bits = 32 hex chars
            assert len(result.sha1) == 40  # SHA1 = 160 bits = 40 hex chars
            assert len(result.sha256) == 64  # SHA256 = 256 bits = 64 hex chars