Verena Rieser

159 papers A* 15A 5B 21Journal 72Unranked 42
YearRankTypeTitle / Venue / Authors
2026 J jnl
CoRR
Michael Henry Tessler, Georgina Evans, Michiel A. Bakker, Iason Gabriel, Sophie Bridgers, Rishub Jain, Raphael Koster, Verena Rieser, Anca Dragan, Matthew Botvinick, Christopher Summerfield
2026 J jnl
Trans. Mach. Learn. Res.
Pushkar Mishra, Charvi Rastogi, Stephen R. Pfohl, Alicia Parrish, Tian Huey Teh, Roma Patel, Mark Diaz, Ding Wang, Michela Paganini, Vinodkumar Prabhakaran, Lora Aroyo, Verena Rieser
2025 J jnl
CoRR
Ding Wang, Mark Díaz, Charvi Rastogi, Aida Mostafazadeh Davani, Vinodkumar Prabhakaran, Pushkar Mishra, Roma Patel, Alicia Parrish, Zoe Ashwood, Michela Paganini, Tian Huey Teh, Verena Rieser, Lora Aroyo
2025 A* conf
ICLR
Canfer Akbulut, Kevin Robinson, Maribeth Rauh, Isabela Albuquerque, Olivia Wiles, Laura Weidinger, Verena Rieser, Yana Hasson, Nahema Marchal, Iason Gabriel, William Isaac, Lisa Anne Hendricks
2025 conf
EMNLP (Findings)
Shravan Nayak, Mehar Bhatia, Xiaofeng Zhang, Verena Rieser, Lisa Anne Hendricks, Sjoerd van Steenkiste, Yash Goyal, Karolina Stanczak, Aishwarya Agrawal
2025 J jnl
CoRR
Shravan Nayak, Mehar Bhatia, Xiaofeng Zhang, Verena Rieser, Lisa Anne Hendricks, Sjoerd van Steenkiste, Yash Goyal, Karolina Stanczak, Aishwarya Agrawal
2025 J jnl
CoRR
Lujain Ibrahim, Canfer Akbulut, Rasmi Elasmar, Charvi Rastogi, Minsuk Kahng, Meredith Ringel Morris, Kevin R. McKee, Verena Rieser, Murray Shanahan, Laura Weidinger
2025 J jnl
CoRR
Pushkar Mishra, Charvi Rastogi, Stephen R. Pfohl, Alicia Parrish, Roma Patel, Mark Diaz, Ding Wang, Michela Paganini, Vinodkumar Prabhakaran, Lora Aroyo, Verena Rieser
2025 A* conf
EMNLP
Taylor Sorensen, Pushkar Mishra, Roma Patel, Michael Henry Tessler, Michiel A. Bakker, Georgina Evans, Iason Gabriel, Noah D. Goodman, Verena Rieser
2025 J jnl
CoRR
Taylor Sorensen, Pushkar Mishra, Roma Patel, Michael Henry Tessler, Michiel A. Bakker, Georgina Evans, Iason Gabriel, Noah D. Goodman, Verena Rieser
2025 J jnl
CoRR
Charvi Rastogi, Tian Huey Teh, Pushkar Mishra, Roma Patel, Ding Wang, Mark Díaz, Alicia Parrish, Aida Mostafazadeh Davani, Zoe Ashwood, Michela Paganini, Vinodkumar Prabhakaran, Verena Rieser, Lora Aroyo
2024 conf
AIES (1)
Canfer Akbulut, Laura Weidinger, Arianna Manzini, Iason Gabriel, Verena Rieser
2024 conf
AIES (1)
Katherine M. Collins, Najoung Kim, Yonatan Bitton, Verena Rieser, Shayegan Omidshafiei, Yushi Hu, Sherol Chen, Senjuti Dutta, Minsuk Chang, Kimin Lee, Youwei Liang, Georgina Evans, Sahil Singla, Gang Li, Adrian Weller, Junfeng He, Deepak Ramachandran, Krishnamurthy Dj Dvijotham
2024 J jnl
CoRR
Katherine M. Collins, Najoung Kim, Yonatan Bitton, Verena Rieser, Shayegan Omidshafiei, Yushi Hu, Sherol Chen, Senjuti Dutta, Minsuk Chang, Kimin Lee, Youwei Liang, Georgina Evans, Sahil Singla, Gang Li, Adrian Weller, Junfeng He, Deepak Ramachandran, Krishnamurthy Dj Dvijotham
2024 conf
AIES (1)
Maribeth Rauh, Nahema Marchal, Arianna Manzini, Lisa Anne Hendricks, Ramona Comanescu, Canfer Akbulut, Tom Stepleton, Juan Mateos-Garcia, A. Stevie Bergman, Jackie Kay, Conor Griffin, Ben Bariach, Iason Gabriel, Verena Rieser, William Isaac, Laura Weidinger
2024 J jnl
CoRR
Charvi Rastogi, Tian Huey Teh, Pushkar Mishra, Roma Patel, Zoe Ashwood, Aida Mostafazadeh Davani, Mark Diaz, Michela Paganini, Alicia Parrish, Ding Wang, Vinodkumar Prabhakaran, Lora Aroyo, Verena Rieser
2024 J jnl
CoRR
Marco Casadio, Tanvi Dinkar, Ekaterina Komendantskaya, Luca Arnaboldi, Omri Isac, Matthew L. Daggitt, Guy Katz, Verena Rieser, Oliver Lemon
2024 A* conf
EMNLP
Laura Weidinger, John Mellor, Bernat Guillen Pegueroles, Nahema Marchal, Ravin Kumar, Kristian Lum, Canfer Akbulut, Mark Diaz, A. Stevie Bergman, Mikel Rodriguez, Verena Rieser, William Isaac
2024 J jnl
CoRR
Laura Weidinger, John Mellor, Bernat Guillen Pegueroles, Nahema Marchal, Ravin Kumar, Kristian Lum, Canfer Akbulut, Mark Diaz, A. Stevie Bergman, Mikel Rodriguez, Verena Rieser, William Isaac
2024 conf
FAccT
Arianna Manzini, Geoff Keeling, Nahema Marchal, Kevin R. McKee, Verena Rieser, Iason Gabriel
2024 J jnl
CoRR
Iason Gabriel, Arianna Manzini, Geoff Keeling, Lisa Anne Hendricks, Verena Rieser, Hasan Iqbal, Nenad Tomasev, Ira Ktena, Zachary Kenton, Mikel Rodriguez, Seliem El-Sayed, Sasha Brown, Canfer Akbulut, Andrew Trask, Edward Hughes, A. Stevie Bergman, Renee Shelby, Nahema Marchal, Conor Griffin, Juan Mateos-Garcia, Laura Weidinger, Winnie Street, Benjamin Lange, Alex Ingerman, Alison Lentz, Reed Enger, Andrew Barakat, Victoria Krakovna, John Oliver Siy, Zeb Kurth-Nelson, Amanda McCroskery, Vijay Bolina, Harry Law, Murray Shanahan, Lize Alberts, Borja Balle, Sarah de Haas, Yetunde Ibitoye, Allan Dafoe, Beth Goldberg, Sébastien Krier, Alexander Reese, Sims Witherspoon, Will Hawkins, Maribeth Rauh, Don Wallace, Matija Franklin, Josh A. Goldstein, Joel Lehman, Michael Klenk, Shannon Vallor, Courtney Biles, Meredith Ringel Morris, Helen King, Blaise Agüera y Arcas, William Isaac, James Manyika
2023 conf
FoMLAS@CAV
Marco Casadio, Luca Arnaboldi, Matthew L. Daggitt, Omri Isac, Tanvi Dinkar, Daniel Kienitz, Verena Rieser, Ekaterina Komendantskaya
2023 J jnl
CoRR
Marco Casadio, Luca Arnaboldi, Matthew L. Daggitt, Omri Isac, Tanvi Dinkar, Daniel Kienitz, Verena Rieser, Ekaterina Komendantskaya
2023 conf
ACL (Findings)
Lu Yu, Verena Rieser
2023 J jnl
CoRR
Gavin Abercrombie, Verena Rieser, Dirk Hovy
2023 B conf
SIGDIAL
Neeraj Cherakara, Finny Varghese, Sheena Shabana, Nivan Nelson, Abhiram Karukayil, Rohith Kulothungan, Mohammed Afil Farhan, Birthe Nesset, Meriam Moujahid, Tanvi Dinkar, Verena Rieser, Oliver Lemon
2023 J jnl
CoRR
Neeraj Cherakara, Finny Varghese, Sheena Shabana, Nivan Nelson, Abhiram Karukayil, Rohith Kulothungan, Mohammed Afil Farhan, Birthe Nesset, Meriam Moujahid, Tanvi Dinkar, Verena Rieser, Oliver Lemon
2023 J jnl
CoRR
Bruce W. Wilson, Yann Schlosser, Rayane Tarkany, Meriam Moujahid, Birthe Nesset, Tanvi Dinkar, Verena Rieser
2023 A* conf
EMNLP
Gavin Abercrombie, Amanda Cercas Curry, Tanvi Dinkar, Verena Rieser, Zeerak Talat
2023 J jnl
CoRR
Anya Belz, Craig Thomson, Ehud Reiter, Gavin Abercrombie, Jose Maria Alonso-Moral, Mohammad Arvan, Jackie Chi Kit Cheung, Mark Cieliebak, Elizabeth Clark, Kees van Deemter, Tanvi Dinkar, Ondrej Dusek, Steffen Eger, Qixiang Fang, Albert Gatt, Dimitra Gkatzia, Javier González-Corbelle, Dirk Hovy, Manuela Hürlimann, Takumi Ito, John D. Kelleher, Filip Klubicka, Huiyuan Lai, Chris van der Lee, Emiel van Miltenburg, Yiru Li, Saad Mahamood, Margot Mieskes, Malvina Nissim, Natalie Parde, Ondrej Plátek, Verena Rieser, Pablo Mosteiro Romero, Joel R. Tetreault, Antonio Toral, Xiaojun Wan, Leo Wanner, Lewis Watson, Diyi Yang
2023 A* conf
EMNLP
Georgios Pantazopoulos, Malvina Nikandrou, Amit Parekh, Bhathiya Hemanthage, Arash Eshghi, Ioannis Konstas, Verena Rieser, Oliver Lemon, Alessandro Suglia
2023 J jnl
CoRR
Georgios Pantazopoulos, Malvina Nikandrou, Amit Parekh, Bhathiya Hemanthage, Arash Eshghi, Ioannis Konstas, Verena Rieser, Oliver Lemon, Alessandro Suglia
2023 A* conf
IJCAI
Lu Yu, Malvina Nikandrou, Jiali Jin, Verena Rieser
2023 J jnl
CoRR
Lu Yu, Malvina Nikandrou, Jiali Jin, Verena Rieser
2023 J jnl
CoRR
Elisa Leonardelli, Alexandra Uma, Gavin Abercrombie, Dina Almanea, Valerio Basile, Tommaso Fornaciari, Barbara Plank, Verena Rieser, Massimo Poesio
2023 conf
SemEval@ACL
Elisa Leonardelli, Gavin Abercrombie, Dina Almanea, Valerio Basile, Tommaso Fornaciari, Barbara Plank, Verena Rieser, Alexandra Uma, Massimo Poesio
2023 J jnl
CoRR
Laura Weidinger, Maribeth Rauh, Nahema Marchal, Arianna Manzini, Lisa Anne Hendricks, Juan Mateos-Garcia, A. Stevie Bergman, Jackie Kay, Conor Griffin, Ben Bariach, Iason Gabriel, Verena Rieser, William Isaac
2023 conf
ACL (Findings)
Sabrina Chiesurin, Dimitris Dimakopoulos, Marco Antonio Sobrevilla Cabezudo, Arash Eshghi, Ioannis Papaioannou, Verena Rieser, Ioannis Konstas
2023 J jnl
CoRR
Sabrina Chiesurin, Dimitris Dimakopoulos, Marco Antonio Sobrevilla Cabezudo, Arash Eshghi, Ioannis Papaioannou, Verena Rieser, Ioannis Konstas
2023 J jnl
CoRR
Yi-Ling Chung, Gavin Abercrombie, Florence Enock, Jonathan Bright, Verena Rieser
2023 conf
SemEval@ACL
Nikolas Vitsakis, Amit Parekh, Tanvi Dinkar, Gavin Abercrombie, Ioannis Konstas, Verena Rieser
2023 J jnl
CoRR
Nikolas Vitsakis, Amit Parekh, Tanvi Dinkar, Gavin Abercrombie, Ioannis Konstas, Verena Rieser
2022 J jnl
CoRR
Lu Yu, Verena Rieser
2022 B conf
SIGDIAL
Alessandro Suglia, Bhathiya Hemanthage, Malvina Nikandrou, Georgios Pantazopoulos, Amit Parekh, Arash Eshghi, Claudio Greco, Ioannis Konstas, Oliver Lemon, Verena Rieser
2022 J jnl
CoRR
Alessandro Suglia, José Lopes, Emanuele Bastianelli, Andrea Vanzo, Shubham Agarwal, Malvina Nikandrou, Lu Yu, Ioannis Konstas, Verena Rieser
2022 B conf
SIGDIAL
A. Stevie Bergman, Gavin Abercrombie, Shannon L. Spruit, Dirk Hovy, Emily Dinan, Y-Lan Boureau, Verena Rieser
2022 ed.
NLPerspectives@LREC
Gavin Abercrombie, Valerio Basile, Sara Tonelli, Verena Rieser, Alexandra Uma
2022 J jnl
CoRR
Shikib Mehri, Jinho Choi, Luis Fernando D'Haro, Jan Deriu, Maxine Eskénazi, Milica Gasic, Kallirroi Georgila, Dilek Hakkani-Tur, Zekang Li, Verena Rieser, Samira Shaikh, David R. Traum, Yi-Ting Yeh, Zhou Yu, Yizhe Zhang, Chen Zhang
2022 conf
AACL/IJCNLP (2)
Gavin Abercrombie, Verena Rieser
2022 J jnl
CoRR
Gavin Abercrombie, Verena Rieser
2022 conf
ACL (1)
Emily Dinan, Gavin Abercrombie, A. Stevie Bergman, Shannon L. Spruit, Dirk Hovy, Y-Lan Boureau, Verena Rieser
2022 J jnl
CoRR
Malvina Nikandrou, Lu Yu, Alessandro Suglia, Ioannis Konstas, Verena Rieser
2022 J jnl
CoRR
Marco Casadio, Ekaterina Komendantskaya, Verena Rieser, Matthew L. Daggitt, Daniel Kienitz, Luca Arnaboldi, Wen Kokke
2021 J jnl
CoRR
Xinnuo Xu, Ondrej Dusek, Verena Rieser, Ioannis Konstas
2021 conf
ACL/IJCNLP (1)
Xinnuo Xu, Ondrej Dusek, Verena Rieser, Ioannis Konstas
2021 J jnl
CoRR
Gavin Abercrombie, Amanda Cercas Curry, Mugdha Pandya, Verena Rieser
2021 J jnl
CoRR
Emily Dinan, Gavin Abercrombie, A. Stevie Bergman, Shannon L. Spruit, Dirk Hovy, Y-Lan Boureau, Verena Rieser
2021 J jnl
CoRR
Amanda Cercas Curry, Gavin Abercrombie, Verena Rieser
2021 conf
EMNLP (1)
Amanda Cercas Curry, Gavin Abercrombie, Verena Rieser
2021 conf
EMNLP (Findings)
Xinnuo Xu, Ondrej Dusek, Shashi Narayan, Verena Rieser, Ioannis Konstas
2021 J jnl
CoRR
Xinnuo Xu, Ondrej Dusek, Shashi Narayan, Verena Rieser, Ioannis Konstas
2021 conf
ACL/IJCNLP (1)
Karin Sevegnani, David M. Howcroft, Ioannis Konstas, Verena Rieser
2021 J jnl
CoRR
Karin Sevegnani, David M. Howcroft, Ioannis Konstas, Verena Rieser
2021 conf
EMNLP (1)
David M. Howcroft, Verena Rieser
2020 J jnl
Comput. Speech Lang.
Ondrej Dusek, Jekaterina Novikova, Verena Rieser
2020 A* conf
ACL
Xinnuo Xu, Ondrej Dusek, Jingyi Li, Verena Rieser, Ioannis Konstas
2020 A* conf
ACL
Shubham Agarwal, Trung Bui, Joon-Young Lee, Ioannis Konstas, Verena Rieser
2020 J jnl
CoRR
Shubham Agarwal, Trung Bui, Joon-Young Lee, Ioannis Konstas, Verena Rieser
2020 conf
EMNLP (1)
Emanuele Bastianelli, Andrea Vanzo, Pawel Swietojanski, Verena Rieser
2020 J jnl
CoRR
Emanuele Bastianelli, Andrea Vanzo, Pawel Swietojanski, Verena Rieser
2020 B conf
INLG
David M. Howcroft, Anya Belz, Miruna-Adriana Clinciu, Dimitra Gkatzia, Sadid A. Hasan, Saad Mahamood, Simon Mille, Emiel van Miltenburg, Sashank Santhanam, Verena Rieser
2019 B conf
SIGdial
Amanda Cercas Curry, Verena Rieser
2019 J jnl
CoRR
Amanda Cercas Curry, Verena Rieser
2019 B conf
INLG
Ondrej Dusek, Karin Sevegnani, Ioannis Konstas, Verena Rieser
2019 J jnl
CoRR
Ondrej Dusek, Karin Sevegnani, Ioannis Konstas, Verena Rieser
2019 conf
IWSDS
Xingkun Liu, Arash Eshghi, Pawel Swietojanski, Verena Rieser
2019 J jnl
CoRR
Xingkun Liu, Arash Eshghi, Pawel Swietojanski, Verena Rieser
2019 J jnl
CoRR
Ondrej Dusek, Jekaterina Novikova, Verena Rieser
2019 B conf
IVA
Verena Rieser
2019 B conf
INLG
Ondrej Dusek, David M. Howcroft, Verena Rieser
2019 J jnl
CoRR
Ondrej Dusek, David M. Howcroft, Verena Rieser
2019 B conf
SIGdial
Simon Keizer, Ondrej Dusek, Xingkun Liu, Verena Rieser
2019 J jnl
CoRR
Simon Keizer, Ondrej Dusek, Xingkun Liu, Verena Rieser
2018 conf
EthNLP@NAACL-HLT
Amanda Cercas Curry, Verena Rieser
2018 conf
SCAI@EMNLP
Shubham Agarwal, Ondrej Dusek, Ioannis Konstas, Verena Rieser
2018 J jnl
CoRR
Shubham Agarwal, Ondrej Dusek, Ioannis Konstas, Verena Rieser
2018 A* conf
EMNLP
Xinnuo Xu, Ondrej Dusek, Ioannis Konstas, Verena Rieser
2018 J jnl
CoRR
Xinnuo Xu, Ondrej Dusek, Ioannis Konstas, Verena Rieser
2018 B conf
INLG
Ondrej Dusek, Jekaterina Novikova, Verena Rieser
2018 J jnl
CoRR
Ondrej Dusek, Jekaterina Novikova, Verena Rieser
2018 B conf
INLG
Shubham Agarwal, Ondrej Dusek, Ioannis Konstas, Verena Rieser
2018 J jnl
CoRR
Shubham Agarwal, Ondrej Dusek, Ioannis Konstas, Verena Rieser
2018 conf
NAACL-HLT (2)
Jekaterina Novikova, Ondrej Dusek, Verena Rieser
2018 J jnl
CoRR
Jekaterina Novikova, Ondrej Dusek, Verena Rieser
2018 J jnl
CoRR
Simon Keizer, Verena Rieser
2017 J jnl
CoRR
Amanda Cercas Curry, Helen F. Hastie, Verena Rieser
2017 conf
ISIAA@ICMI
Amanda Cercas Curry, Helen F. Hastie, Verena Rieser
2017 J jnl
Adv. Robotics
Christian Landsiedel, Verena Rieser, Matthew Walter, Dirk Wollherr
2017 J jnl
CoRR
Ioannis Papaioannou, Amanda Cercas Curry, Jose L. Part, Igor Shalyminov, Xinnuo Xu, Yanchao Yu, Ondrej Dusek, Verena Rieser, Oliver Lemon
2017 J jnl
CoRR
Jekaterina Novikova, Ondrej Dusek, Verena Rieser
2017 J jnl
IEEE Comput. Intell. Mag.
Dimitra Gkatzia, Oliver Lemon, Verena Rieser
2017 J jnl
CoRR
Ondrej Dusek, Jekaterina Novikova, Verena Rieser
2017 J jnl
Adv. Robotics
Verena Rieser, Matthew Walter, Dirk Wollherr
2017 conf
SIGDIAL Conference
Jekaterina Novikova, Ondrej Dusek, Verena Rieser
2017 J jnl
CoRR
Jekaterina Novikova, Ondrej Dusek, Verena Rieser
2017 A* conf
EMNLP
Jekaterina Novikova, Ondrej Dusek, Amanda Cercas Curry, Verena Rieser
2017 J jnl
CoRR
Jekaterina Novikova, Ondrej Dusek, Amanda Cercas Curry, Verena Rieser
2016 B conf
INLG
Jekaterina Novikova, Oliver Lemon, Verena Rieser
2016 J jnl
CoRR
Jekaterina Novikova, Oliver Lemon, Verena Rieser
2016 B conf
FUZZ-IEEE
Dimitra Gkatzia, Verena Rieser, Oliver Lemon
2016 B ed.
INLG
Amy Isard, Verena Rieser, Dimitra Gkatzia
2016 J jnl
Comput. Speech Lang.
Nina Dethlefs, Helen F. Hastie, Heriberto Cuayáhuitl, Yanchao Yu, Verena Rieser, Oliver Lemon
2016 J jnl
CoRR
Verena Rieser, Oliver Lemon
2016 conf
ACL (2)
Dimitra Gkatzia, Oliver Lemon, Verena Rieser
2016 J jnl
CoRR
Dimitra Gkatzia, Oliver Lemon, Verena Rieser
2016 B conf
LREC
Phil J. Bartie, William A. Mackaness, Dimitra Gkatzia, Verena Rieser
2016 B conf
INLG
Jekaterina Novikova, Verena Rieser
2016 conf
SemEval@NAACL-HLT
Eshrag Refaee, Verena Rieser
2015 conf
ENLG
Dimitra Gkatzia, Amanda Cercas Curry, Verena Rieser, Oliver Lemon
2015 conf
ICAART (1)
Marta Vallejo, Verena Rieser, David W. Corne
2015 conf
HLT-NAACL
Eshrag Refaee, Verena Rieser
2015 A* conf
EMNLP
Dimitra Gkatzia, Verena Rieser, Phil J. Bartie, William A. Mackaness
2015 conf
ENLG
Amanda Cercas Curry, Dimitra Gkatzia, Verena Rieser
2015 J jnl
J. Comput. Sci.
Marta Vallejo, Verena Rieser, David W. Corne
2014 B conf
LREC
Eshrag Refaee, Verena Rieser
2014 A conf
EACL
Nina Dethlefs, Heriberto Cuayáhuitl, Helen F. Hastie, Verena Rieser, Oliver Lemon
2014 conf
ANLP@EMNLP
Eshrag Refaee, Verena Rieser
2014 J jnl
IEEE ACM Trans. Audio Speech Lang. Process.
Verena Rieser, Oliver Lemon, Simon Keizer
2014 ch.
Natural Language Generation in Interactive Systems
Oliver Lemon, Srinivasan Janarthanam, Verena Rieser
2014 conf
SIGDIAL Conference
Helen F. Hastie, Marie-Aude Aufaure, Panos Alexopoulos, Hugues Bouchard, Catherine Breslin, Heriberto Cuayáhuitl, Nina Dethlefs, Milica Gasic, James Henderson, Oliver Lemon, Xingkun Liu, Peter Mika, Nesrine Ben Mustapha, Tim Potter, Verena Rieser, Blaise Thomson, Pirros Tsiakoulis, Yves Vanrompay, Boris Villazón-Terrazas, Majid Yazdani, Steve J. Young, Yanchao Yu
2013 J jnl
Environ. Model. Softw.
Dave Murray-Rust, Verena Rieser, Derek T. Robinson, Vesna Milicic, Mark Rounsevell
2013 conf
SIGDIAL Conference
Helen F. Hastie, Marie-Aude Aufaure, Panos Alexopoulos, Heriberto Cuayáhuitl, Nina Dethlefs, Milica Gasic, James Henderson, Oliver Lemon, Xingkun Liu, Peter Mika, Nesrine Ben Mustapha, Verena Rieser, Blaise Thomson, Pirros Tsiakoulis, Yves Vanrompay
2013 conf
ICAART (Revised Selected Papers)
Marta Vallejo, David W. Corne, Verena Rieser
2013 conf
ICAART (2)
Marta Vallejo, David W. Corne, Verena Rieser
2012 J jnl
Comput. Environ. Urban Syst.
Derek T. Robinson, David Murray-Rust, Verena Rieser, Vesna Milicic, Mark D. Rounsevell
2012 conf
EMNLP-CoNLL
Nina Dethlefs, Helen Wright Hastie, Verena Rieser, Oliver Lemon
2012 B conf
INLG
Nina Dethlefs, Helen Wright Hastie, Verena Rieser, Oliver Lemon
2011 conf
ENLG
Verena Rieser, Simon Keizer, Oliver Lemon, Xingkun Liu
2011 J jnl
Comput. Linguistics
Verena Rieser, Oliver Lemon
2011 book
Verena Rieser, Oliver Lemon
2010 B conf
INLG
Oliver Lemon, Srinivasan Janarthanam, Verena Rieser
2010 J jnl
Nat. Lang. Eng.
Verena Rieser, Oliver Lemon
2010 conf
Empirical Methods in Natural Language Generation
Verena Rieser, Oliver Lemon
2010 A* conf
ACL
Verena Rieser, Oliver Lemon, Xingkun Liu
2009 J jnl
Nat. Lang. Eng.
Verena Rieser, Oliver Lemon
2009 A conf
EACL
Verena Rieser, Oliver Lemon
2009 A conf
INTERSPEECH
Cédric Boidin, Verena Rieser, Lonneke van der Plas, Oliver Lemon, Jonathan Chevelu
2008 B conf
LREC
Verena Rieser, Oliver Lemon
2008
Verena Rieser
2008 A* conf
ACL
Verena Rieser, Oliver Lemon
2007 A conf
INTERSPEECH
Verena Rieser, Oliver Lemon
2006 A conf
INTERSPEECH
Verena Rieser, Oliver Lemon
2006 B conf
LREC
Ivana Kruijff-Korbayová, Tilman Becker, Nate Blaylock, Ciprian Gerstenberger, Michael Kaisser, Peter Poller, Verena Rieser, Jan Schehl
2006 conf
NLPXML@EACL
Ivana Kruijff-Korbayová, Verena Rieser, Ciprian Gerstenberger, Jan Schehl, Tilman Becker
2006 A* conf
ACL
Verena Rieser, Oliver Lemon
2006 conf
SLT
Verena Rieser, Oliver Lemon
2005 conf
SIGDIAL Workshop
Verena Rieser, Ivana Kruijff-Korbayová, Oliver Lemon
2005 conf
ENLG
Ivana Kruijff-Korbayová, Nate Blaylock, Ciprian Gerstenberger, Verena Rieser, Tilman Becker, Michael Kaisser, Peter Poller, Jan Schehl
2005 A* conf
ACL
Verena Rieser, Johanna D. Moore
tests/unit/test_decompile_analysis.py
← Index tests/unit/test_decompile_analysis.py python
"""Unit tests (mocked Binary Ninja) for analysis modules:
- bninja/analysis/cfg.py — CFGAnalysis
- bninja/analysis/disassembly.py — DisassemblyAnalysis
- bninja/analysis/low_level.py — LowLevelAnalysis
"""
import sys
import pytest
from unittest.mock import MagicMock

from tests.unit.conftest_binja_stubs import (
    install_binja_stubs,
    BranchType,
    InstructionTextTokenType,
    MockBasicBlock,
    MockEdge,
    MockFunction,
    MockToken,
    MockDisassemblyLine,
    MockBinaryView,
    MockSymbol,
    SymbolType,
    LowLevelILOperation,
)

install_binja_stubs()

from redb.extractors.decompiler.bninja.analysis.cfg import CFGAnalysis
from redb.extractors.decompiler.bninja.analysis.disassembly import DisassemblyAnalysis
from redb.extractors.decompiler.bninja.arch.x86 import Arch_x86


# ============================================================================
# 9a. CFGAnalysis
# ============================================================================


class TestCFGCyclomaticComplexity:
    def test_cyclomatic_complexity_linear(self):
        """Single block, no edges: E - N + 2 = 0 - 1 + 2 = 1."""
        block = MockBasicBlock(start=0x1000, end=0x1010, outgoing_edges=[])
        func = MockFunction(start=0x1000, basic_blocks=[block])
        cfg = CFGAnalysis(func)
        result = cfg.extract_function_cfg()
        assert result["cyclomatic_complexity"] == 1

    def test_cyclomatic_complexity_branch(self):
        """Diamond: 4 blocks, 4 edges -> 4 - 4 + 2 = 2."""
        entry = MockBasicBlock(start=0x1000, end=0x1010)
        true_b = MockBasicBlock(start=0x1010, end=0x1020)
        false_b = MockBasicBlock(start=0x1020, end=0x1030)
        merge = MockBasicBlock(start=0x1030, end=0x1040)

        entry.outgoing_edges = [MockEdge(target=true_b), MockEdge(target=false_b)]
        true_b.outgoing_edges = [MockEdge(target=merge)]
        false_b.outgoing_edges = [MockEdge(target=merge)]
        merge.outgoing_edges = []

        func = MockFunction(start=0x1000, basic_blocks=[entry, true_b, false_b, merge])
        cfg = CFGAnalysis(func)
        result = cfg.extract_function_cfg()
        assert result["cyclomatic_complexity"] == 2

    def test_cyclomatic_complexity_loop(self):
        """Loop: 3 blocks, 3 edges -> 3 - 3 + 2 = 2."""
        header = MockBasicBlock(start=0x1000, end=0x1010)
        body = MockBasicBlock(start=0x1010, end=0x1020)
        exit_b = MockBasicBlock(start=0x1020, end=0x1030)

        header.outgoing_edges = [MockEdge(target=body), MockEdge(target=exit_b)]
        body.outgoing_edges = [MockEdge(target=header)]
        exit_b.outgoing_edges = []

        func = MockFunction(start=0x1000, basic_blocks=[header, body, exit_b])
        cfg = CFGAnalysis(func)
        result = cfg.extract_function_cfg()
        assert result["cyclomatic_complexity"] == 2


class TestCFGExtractFunctionCFG:
    def _make_simple_cfg(self):
        """Create a simple two-block CFG for testing structure."""
        entry = MockBasicBlock(start=0x1000, end=0x1010)
        exit_b = MockBasicBlock(start=0x1010, end=0x1020)

        entry.outgoing_edges = [MockEdge(source=entry, target=exit_b, edge_type=BranchType.UnconditionalBranch)]
        exit_b.incoming_edges = [MockEdge(source=entry, target=exit_b)]
        exit_b.outgoing_edges = []
        entry.incoming_edges = []

        func = MockFunction(start=0x1000, basic_blocks=[entry, exit_b])
        return func

    def test_extract_function_cfg_structure(self):
        func = self._make_simple_cfg()
        cfg = CFGAnalysis(func)
        result = cfg.extract_function_cfg()
        assert "function_address" not in result
        # New schema: no "blocks" or "measures" nesting
        assert "blocks" not in result
        assert "measures" not in result

    def test_function_cfg_new_keys(self):
        """Assert all expected keys are present in the new output dict."""
        func = self._make_simple_cfg()
        cfg = CFGAnalysis(func)
        result = cfg.extract_function_cfg()
        expected_keys = [
            "cfg_topology_hash",
            "block_count",
            "edge_count",
            "llil_total_operations",
            "call_count",
            "cyclomatic_complexity",
            "loop_count",
            "max_depth",
            "max_fan_out",
            "md_index_topdown",
            "md_index_bottomup",
            "prime_product_llil",
            "cfg_feature_tlsh",
            "wl_minhash",
            "bb_features",
            "cfg_adjacency",
        ]
        for key in expected_keys:
            assert key in result, f"Missing key: {key}"

    def test_returns_none_for_empty_blocks(self):
        func = MockFunction(start=0x1000, basic_blocks=[])
        cfg = CFGAnalysis(func)
        assert cfg.extract_function_cfg() is None


class TestCFGTopologyHash:
    def _make_two_block_cfg(self):
        entry = MockBasicBlock(start=0x1000, end=0x1010)
        exit_b = MockBasicBlock(start=0x1010, end=0x1020)
        entry.outgoing_edges = [MockEdge(target=exit_b)]
        exit_b.outgoing_edges = []
        return MockFunction(start=0x1000, basic_blocks=[entry, exit_b])

    def test_topology_hash_is_16_bytes(self):
        func = self._make_two_block_cfg()
        cfg = CFGAnalysis(func)
        result = cfg.extract_function_cfg()
        assert isinstance(result["cfg_topology_hash"], bytes)
        assert len(result["cfg_topology_hash"]) == 16

    def test_topology_hash_deterministic(self):
        func = self._make_two_block_cfg()
        r1 = CFGAnalysis(func).extract_function_cfg()
        r2 = CFGAnalysis(func).extract_function_cfg()
        assert r1["cfg_topology_hash"] == r2["cfg_topology_hash"]


class TestCFGLoopCount:
    def test_no_loops(self):
        entry = MockBasicBlock(start=0x1000, end=0x1010)
        exit_b = MockBasicBlock(start=0x1010, end=0x1020)
        entry.outgoing_edges = [MockEdge(target=exit_b)]
        exit_b.outgoing_edges = []
        func = MockFunction(start=0x1000, basic_blocks=[entry, exit_b])
        result = CFGAnalysis(func).extract_function_cfg()
        assert result["loop_count"] == 0

    def test_single_loop(self):
        header = MockBasicBlock(start=0x1000, end=0x1010)
        body = MockBasicBlock(start=0x1010, end=0x1020)
        exit_b = MockBasicBlock(start=0x1020, end=0x1030)
        header.outgoing_edges = [MockEdge(target=body), MockEdge(target=exit_b)]
        body.outgoing_edges = [MockEdge(target=header)]
        exit_b.outgoing_edges = []
        func = MockFunction(start=0x1000, basic_blocks=[header, body, exit_b])
        result = CFGAnalysis(func).extract_function_cfg()
        assert result["loop_count"] == 1


class TestCFGMaxDepth:
    def test_max_depth_linear(self):
        entry = MockBasicBlock(start=0x1000, end=0x1010)
        b1 = MockBasicBlock(start=0x1010, end=0x1020)
        b2 = MockBasicBlock(start=0x1020, end=0x1030)
        entry.outgoing_edges = [MockEdge(target=b1)]
        b1.outgoing_edges = [MockEdge(target=b2)]
        b2.outgoing_edges = []
        func = MockFunction(start=0x1000, basic_blocks=[entry, b1, b2])
        result = CFGAnalysis(func).extract_function_cfg()
        assert result["max_depth"] == 2

    def test_max_depth_single_block(self):
        block = MockBasicBlock(start=0x1000, end=0x1010, outgoing_edges=[])
        func = MockFunction(start=0x1000, basic_blocks=[block])
        result = CFGAnalysis(func).extract_function_cfg()
        assert result["max_depth"] == 0


class TestCFGCollectBlockLlilOps:
    """Test that _collect_block_llil_ops correctly maps LLIL data to native blocks."""

    def test_llil_fields_nonzero_with_mock_llil(self):
        """When LLIL is available, llil_total_operations and call_count should be non-zero."""
        # Two native blocks
        entry = MockBasicBlock(start=0x1000, end=0x1010)
        exit_b = MockBasicBlock(start=0x1010, end=0x1020)
        entry.outgoing_edges = [MockEdge(target=exit_b)]
        exit_b.outgoing_edges = []

        # LLIL instructions: SET_REG, CALL in first block; STORE, RET in second
        llil_instrs_1 = [
            MockLLILInstruction(LowLevelILOperation.LLIL_SET_REG),
            MockLLILInstruction(LowLevelILOperation.LLIL_CALL),
        ]
        llil_instrs_2 = [
            MockLLILInstruction(LowLevelILOperation.LLIL_STORE),
            MockLLILInstruction(LowLevelILOperation.LLIL_RET),
        ]

        # LLIL basic blocks map back to native blocks via source_block
        llil_bb1 = MockLLILBasicBlock(llil_instrs_1, source_block=entry)
        llil_bb2 = MockLLILBasicBlock(llil_instrs_2, source_block=exit_b)
        llil_func = MockLLILFunction([llil_bb1, llil_bb2])

        func = MockFunction(start=0x1000, basic_blocks=[entry, exit_b], llil=llil_func)
        result = CFGAnalysis(func, llil_function=llil_func).extract_function_cfg()

        assert result["llil_total_operations"] == 4
        assert result["call_count"] == 1
        assert result["prime_product_llil"] != 0

    def test_llil_none_gives_zero_fields(self):
        """Without LLIL, LLIL-dependent fields should be zero."""
        block = MockBasicBlock(start=0x1000, end=0x1010, outgoing_edges=[])
        func = MockFunction(start=0x1000, basic_blocks=[block])
        result = CFGAnalysis(func).extract_function_cfg()

        assert result["llil_total_operations"] == 0
        assert result["call_count"] == 0
        assert result["prime_product_llil"] == 0

    def test_bb_features_with_llil(self):
        """bb_features should reflect LLIL instruction categories when LLIL is available."""
        block = MockBasicBlock(start=0x1000, end=0x1010, outgoing_edges=[])

        llil_instrs = [
            MockLLILInstruction(LowLevelILOperation.LLIL_ADD),
            MockLLILInstruction(LowLevelILOperation.LLIL_LOAD),
            MockLLILInstruction(LowLevelILOperation.LLIL_CALL),
        ]
        llil_bb = MockLLILBasicBlock(llil_instrs, source_block=block)
        llil_func = MockLLILFunction([llil_bb])

        func = MockFunction(start=0x1000, basic_blocks=[block])
        result = CFGAnalysis(func, llil_function=llil_func).extract_function_cfg()

        feats = result["bb_features"]
        assert len(feats) == 1
        assert feats[0][0] == 3  # instruction count = 3
        # At least one non-zero category count (not all OTHER)
        category_counts = feats[0][1:7]
        assert sum(category_counts) > 0


# ============================================================================
# 9b. DisassemblyAnalysis
# ============================================================================


class TestDisassemblyAnalysisGetJson:
    def _make_analysis(self, instructions=None, basic_blocks=None):
        arch = Arch_x86()
        if instructions is None:
            instructions = [
                (
                    [
                        MockToken("push", InstructionTextTokenType.InstructionToken),
                        MockToken(" ", InstructionTextTokenType.TextToken),
                        MockToken("rbp", InstructionTextTokenType.RegisterToken),
                    ],
                    0x1000,
                ),
                (
                    [
                        MockToken("mov", InstructionTextTokenType.InstructionToken),
                        MockToken(" ", InstructionTextTokenType.TextToken),
                        MockToken("rsp", InstructionTextTokenType.RegisterToken),
                    ],
                    0x1003,
                ),
            ]
        if basic_blocks is None:
            basic_blocks = [MockBasicBlock(
                start=0x1000, end=0x1010,
                disassembly_text=[MockDisassemblyLine([MockToken("push rbp")])]
            )]

        func = MockFunction(
            name="test_func",
            start=0x1000,
            basic_blocks=basic_blocks,
            instructions=instructions,
            symbol=MockSymbol(symbol_type=SymbolType.FunctionSymbol, name="test_func"),
            stack_adjustment=MagicMock(value=-8),
            mlil=None,
        )
        bv = MockBinaryView()
        logger = MagicMock()
        return DisassemblyAnalysis(arch, func, bv, logger)

    def test_get_json_basic_structure(self):
        da = self._make_analysis()
        result, errors = da.get_json()
        expected_keys = [
            "disassembled_function_hash",
            "disassembled_function",
            "disassembled_function_no_addresses",
            "disassembled_function_name",
            "disassembled_function_address",
            "instructions_count",
            "function_type",
            "instructions_types",
            "control_flow_count",
            "memory_access_pattern",
            "register_usage",
            "data_references_count",
        ]
        for key in expected_keys:
            assert key in result, f"Missing key: {key}"

    def test_get_json_hash_deterministic(self):
        da = self._make_analysis()
        r1, _ = da.get_json()
        da2 = self._make_analysis()
        r2, _ = da2.get_json()
        assert r1["disassembled_function_hash"] == r2["disassembled_function_hash"]


class TestDisassemblyCollectInstructionTypes:
    def test_collect_instruction_types(self):
        arch = Arch_x86()
        instructions = [
            ([MockToken("MOV", InstructionTextTokenType.InstructionToken)], 0x1000),
            ([MockToken("ADD", InstructionTextTokenType.InstructionToken)], 0x1001),
            ([MockToken("MOV", InstructionTextTokenType.InstructionToken)], 0x1002),
        ]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        types = da.collect_instruction_types()
        assert "DATA_MOVEMENT" in types
        assert "ARITHMETIC" in types

    def test_collect_instruction_types_empty(self):
        arch = Arch_x86()
        func = MockFunction(start=0x1000, instructions=[], symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        types = da.collect_instruction_types()
        assert types == {}


class TestDisassemblyMemoryPatterns:
    def _make_memory_instruction(self, tokens):
        return ([t for t in tokens], 0x1000)

    def test_collect_memory_patterns_stack(self):
        arch = Arch_x86()
        tokens = [
            MockToken("[", InstructionTextTokenType.BeginMemoryOperandToken),
            MockToken("RSP", InstructionTextTokenType.RegisterToken),
            MockToken("+0x8", InstructionTextTokenType.TextToken),
            MockToken("]", InstructionTextTokenType.EndMemoryOperandToken),
        ]
        instructions = [self._make_memory_instruction(tokens)]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        patterns = da.collect_memory_patterns()
        assert "MEM_STACK" in patterns

    def test_collect_memory_patterns_direct(self):
        arch = Arch_x86()
        tokens = [
            MockToken("[", InstructionTextTokenType.BeginMemoryOperandToken),
            MockToken("0x402000", InstructionTextTokenType.TextToken),
            MockToken("]", InstructionTextTokenType.EndMemoryOperandToken),
        ]
        instructions = [self._make_memory_instruction(tokens)]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        patterns = da.collect_memory_patterns()
        assert "MEM_DIRECT" in patterns

    def test_collect_memory_patterns_scaled(self):
        arch = Arch_x86()
        tokens = [
            MockToken("[", InstructionTextTokenType.BeginMemoryOperandToken),
            MockToken("RAX+RCX*4", InstructionTextTokenType.TextToken),
            MockToken("]", InstructionTextTokenType.EndMemoryOperandToken),
        ]
        instructions = [self._make_memory_instruction(tokens)]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        patterns = da.collect_memory_patterns()
        assert "MEM_SCALED_INDEX" in patterns

    def test_collect_memory_patterns_base_offset(self):
        arch = Arch_x86()
        tokens = [
            MockToken("[", InstructionTextTokenType.BeginMemoryOperandToken),
            MockToken("RAX+0x10", InstructionTextTokenType.TextToken),
            MockToken("]", InstructionTextTokenType.EndMemoryOperandToken),
        ]
        instructions = [self._make_memory_instruction(tokens)]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        patterns = da.collect_memory_patterns()
        assert "MEM_BASE_OFFSET" in patterns


class TestDisassemblyRegisterUsage:
    def test_collect_register_usage_gpr(self):
        arch = Arch_x86()
        instructions = [
            ([MockToken("RAX", InstructionTextTokenType.RegisterToken)], 0x1000),
        ]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        regs = da.collect_register_usage()
        assert "GPR" in regs

    def test_collect_register_usage_simd(self):
        arch = Arch_x86()
        instructions = [
            ([MockToken("XMM0", InstructionTextTokenType.RegisterToken)], 0x1000),
        ]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        regs = da.collect_register_usage()
        assert "SIMD" in regs

    def test_collect_register_usage_fpu(self):
        arch = Arch_x86()
        instructions = [
            ([MockToken("ST0", InstructionTextTokenType.RegisterToken)], 0x1000),
        ]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        regs = da.collect_register_usage()
        assert "FPU" in regs


class TestDisassemblyMisc:
    def test_count_data_references(self):
        arch = Arch_x86()
        func = MockFunction(start=0x1000, instructions=[], symbol=MockSymbol(), mlil=None)
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        assert da.count_data_references() == 0

    def test_compute_max_block_size(self):
        arch = Arch_x86()
        blocks = [
            MockBasicBlock(disassembly_text=[MockDisassemblyLine([]) for _ in range(3)]),
            MockBasicBlock(disassembly_text=[MockDisassemblyLine([]) for _ in range(5)]),
        ]
        func = MockFunction(start=0x1000, basic_blocks=blocks, instructions=[], symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        assert da.compute_max_block_size() == 5

    def test_compute_num_calls(self):
        arch = Arch_x86()
        instructions = [
            ([MockToken("CALL", InstructionTextTokenType.InstructionToken)], 0x1000),
            ([MockToken("MOV", InstructionTextTokenType.InstructionToken)], 0x1005),
            ([MockToken("CALL", InstructionTextTokenType.InstructionToken)], 0x1010),
        ]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        assert da.compute_num_calls() == 2

    def test_estimate_stack_size_value(self):
        arch = Arch_x86()
        stack = MagicMock()
        stack.value = -16
        func = MockFunction(start=0x1000, instructions=[], symbol=MockSymbol(), stack_adjustment=stack)
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        assert da.estimate_stack_size() == -16

    def test_estimate_stack_size_int(self):
        arch = Arch_x86()
        func = MockFunction(start=0x1000, instructions=[], symbol=MockSymbol(), stack_adjustment=-8)
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        assert da.estimate_stack_size() == -8

    def test_normalize_opcode(self):
        arch = Arch_x86()
        func = MockFunction(start=0x1000, instructions=[], symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        assert da.normalize_opcode("mov") == "MOV"
        assert da.normalize_opcode("PUSH") == "PUSH"


# ============================================================================
# 9c. LowLevelAnalysis (basic tests with mocked LLIL)
# ============================================================================


class MockLLILInstruction:
    """Mock LLIL instruction for low_level.py tests."""
    def __init__(self, operation, operands=None, address=0):
        self.operation = operation
        self.operands = operands or []
        self.address = address

    def __str__(self):
        return f"LLIL_{self.operation}"


class MockLLILBasicBlock:
    def __init__(self, instructions, source_block=None):
        self._instructions = instructions
        self.source_block = source_block

    def __iter__(self):
        return iter(self._instructions)


class MockLLILFunction:
    def __init__(self, basic_blocks):
        self.basic_blocks = basic_blocks
        self._instructions = []
        for bb in basic_blocks:
            self._instructions.extend(bb._instructions)

    @property
    def instructions(self):
        return iter(self._instructions)

    @property
    def source_function(self):
        mock = MagicMock()
        mock.start = 0x1000
        return mock


class TestLowLevelAnalysisCountControlFlow:
    def test_count_control_flow_instructions(self):
        from redb.extractors.decompiler.bninja.analysis.low_level import LowLevelAnalysis
        instrs = [
            MockLLILInstruction(LowLevelILOperation.LLIL_IF),
            MockLLILInstruction(LowLevelILOperation.LLIL_SET_REG),
            MockLLILInstruction(LowLevelILOperation.LLIL_CALL),
            MockLLILInstruction(LowLevelILOperation.LLIL_GOTO),
        ]
        bb = MockLLILBasicBlock(instrs)
        llil_func = MockLLILFunction([bb])

        func = MockFunction(start=0x1000, llil=llil_func, symbol=MockSymbol())
        func.low_level_il = None
        bv = MockBinaryView()
        bv.arch = MagicMock()
        bv.arch.stack_pointer = "sp"
        la = LowLevelAnalysis(func, bv, MagicMock())
        assert la.count_control_flow_instructions() == 3  # IF, CALL, GOTO


class TestLowLevelAnalysisNumCalls:
    def test_compute_num_calls_llil(self):
        from redb.extractors.decompiler.bninja.analysis.low_level import LowLevelAnalysis
        instrs = [
            MockLLILInstruction(LowLevelILOperation.LLIL_CALL),
            MockLLILInstruction(LowLevelILOperation.LLIL_TAILCALL),
            MockLLILInstruction(LowLevelILOperation.LLIL_SET_REG),
        ]
        bb = MockLLILBasicBlock(instrs)
        llil_func = MockLLILFunction([bb])

        func = MockFunction(start=0x1000, llil=llil_func, symbol=MockSymbol())
        func.low_level_il = None
        bv = MockBinaryView()
        la = LowLevelAnalysis(func, bv, MagicMock())
        assert la.compute_num_calls() == 2


class TestLowLevelAnalysisCollectNormalization:
    def test_collect_low_level(self):
        from redb.extractors.decompiler.bninja.analysis.low_level import LowLevelAnalysis
        instrs = [
            MockLLILInstruction(LowLevelILOperation.LLIL_SET_REG, address=0x1000),
            MockLLILInstruction(LowLevelILOperation.LLIL_STORE, address=0x1004),
        ]
        bb = MockLLILBasicBlock(instrs)
        llil_func = MockLLILFunction([bb])

        func = MockFunction(start=0x1000, llil=llil_func, symbol=MockSymbol())
        func.low_level_il = None
        bv = MockBinaryView()
        la = LowLevelAnalysis(func, bv, MagicMock())
        result, _ = la._collect_low_level_and_with_addr()
        assert len(result) == 2
        # Each item is a list of operation ints
        assert isinstance(result[0], list)

    def test_collect_low_level_with_addr_offset_clamping(self):
        from redb.extractors.decompiler.bninja.analysis.low_level import LowLevelAnalysis
        instrs = [
            MockLLILInstruction(LowLevelILOperation.LLIL_SET_REG, address=0x0FFF),  # Before function start
        ]
        bb = MockLLILBasicBlock(instrs)
        llil_func = MockLLILFunction([bb])

        func = MockFunction(start=0x1000, llil=llil_func, symbol=MockSymbol())
        func.low_level_il = None
        bv = MockBinaryView()
        la = LowLevelAnalysis(func, bv, MagicMock())
        _, result = la._collect_low_level_and_with_addr()
        assert len(result) == 1
        offset, _ = result[0]
        assert offset == 0  # Clamped to 0