H. T. Kung

242 papers A* 42A 14B 32C 14Misc 5Journal 80Unranked 55
YearRankTypeTitle / Venue / Authors
2026 A* conf
AAAI
He-Yen Hsieh, Wei-Te Mark Ting, H. T. Kung
2026 J jnl
CoRR
He-Yen Hsieh, Wei-Te Mark Ting, H. T. Kung
2026 J jnl
CoRR
Mu-Chi Chen, Yu-Hung Kao, Po-Hsuan Huang, Shao-Chun Ho, Hsiang-Yu Tsou, I-Ting Wu, En-Ming Huang, Yu-Kai Hung, Wei-Po Hsin, Cheng Liang, Chia-Heng Tu, Shih-Hao Hung, H. T. Kung
2025 J jnl
IEEE Trans. Cogn. Dev. Syst.
Yu-Jia Chen, Wei Chen, Sai Qian Zhang, Hai-Yan Huang, H. T. Kung
2025 C conf
ISCAS
Vikas Natesh, H. T. Kung
2025 J jnl
CoRR
He-Yen Hsieh, Hong Wang, H. T. Kung
2025 C conf
ISCAS
Matheus Farias, H. T. Kung
2025 J jnl
CoRR
Huandong Chang, Zicheng Ma, Mingyuan Ma, Zhenting Qi, Andrew Sabot, Hong Jiang, H. T. Kung
2025 C conf
ISCAS
Kao-Den Chang, He-Yen Hsieh, H. T. Kung, Ziyun Li, Sai Qian Zhang
2025 C conf
ISCAS
H. T. Kung, Andrew Sabot
2025 J jnl
CoRR
Matheus Farias, Wanghley Martins, H. T. Kung
2025 J jnl
CoRR
Vikas Natesh, H. T. Kung, David Kong
2025 J jnl
CoRR
Vikas Natesh, H. T. Kung
2025 C conf
ISCAS
Matheus Farias, H. T. Kung
2024 J jnl
CoRR
Xiang-Li Lu, Hwai-Jung Hsu, Che-Wei Chou, H. T. Kung, Chen-Hsin Lee, Sheng-Mao Cheng
2024 J jnl
CoRR
Matheus Farias, H. T. Kung
2024 J jnl
CoRR
He-Yen Hsieh, Ziyun Li, Sai Qian Zhang, Wei-Te Mark Ting, Kao-Den Chang, Barbara De Salvo, Chiao Liu, H. T. Kung
2024 J jnl
CoRR
Matheus Farias, H. T. Kung
2023 J jnl
CoRR
Andrew Sabot, Vikas Natesh, H. T. Kung, Wei-Te Ting
2023 J jnl
CoRR
Vikas Natesh, Andrew Sabot, H. T. Kung, Mark Ting
2023 C conf
ICMLA
Surat Teerapittayanon, Marcus Z. Comiter, Bradley McDanel, H. T. Kung
2023 J jnl
CoRR
Surat Teerapittayanon, Marcus Z. Comiter, Bradley McDanel, H. T. Kung
2022 A conf
ISLPED
Ruicong Chen, H. T. Kung, Anantha P. Chandrakasan, Hae-Seung Lee
2022 A* conf
HPCA
Sai Qian Zhang, Bradley McDanel, H. T. Kung
2022 A* conf
CVPR
Xin Dong, Junfeng Guo, Ang Li, Wei-Te Ting, Cong Liu, H. T. Kung
2022 A conf
BMVC
Xin Dong, Hongxu Yin, José M. Álvarez, Jan Kautz, Pavlo Molchanov, H. T. Kung
2022 conf
ECCV (26)
Xin Dong, Sai Qian Zhang, Ang Li, H. T. Kung
2022 J jnl
CoRR
Xin Dong, Sai Qian Zhang, Ang Li, H. T. Kung
2022 A* conf
CVPR
Xin Dong, Barbara De Salvo, Meng Li, Chiao Liu, Zhongnan Qu, H. T. Kung, Ziyun Li
2022 J jnl
CoRR
Xin Dong, Barbara De Salvo, Meng Li, Chiao Liu, Zhongnan Qu, H. T. Kung, Ziyun Li
2021 B conf
IJCNN
Marcelo A. C. Fernandes, H. T. Kung
2021 A conf
SC
H. T. Kung, Vikas Natesh, Andrew Sabot
2021 J jnl
CoRR
Sai Qian Zhang, Bradley McDanel, H. T. Kung
2021 J jnl
CoRR
Xin Dong, Junfeng Guo, Wei-Te Ting, H. T. Kung
2021 C conf
ISCAS
Bradley McDanel, Sai Qian Zhang, H. T. Kung
2021 A* conf
ASPLOS
Sai Qian Zhang, Bradley McDanel, H. T. Kung, Xin Dong
2020 J jnl
CoRR
H. T. Kung, Bradley McDanel, Sai Qian Zhang
2020 conf
EMNLP (Findings)
Wen Tai, H. T. Kung, Xin Dong, Marcus Z. Comiter, Chang-Fu Kuo
2019 A* conf
AAAI
Miriam Cha, Youngjune L. Gwon, H. T. Kung
2019 J jnl
CoRR
Marcus Z. Comiter, Surat Teerapittayanon, H. T. Kung
2019 conf
Blockchain
Surat Teerapittayanon, H. T. Kung
2019 J jnl
CoRR
Surat Teerapittayanon, H. T. Kung
2019 J jnl
CoRR
Bradley McDanel, Sai Qian Zhang, H. T. Kung, Xin Dong
2019 A conf
ICS
Bradley McDanel, Sai Qian Zhang, H. T. Kung, Xin Dong
2019 conf
ASAP
H. T. Kung, Bradley McDanel, Sai Qian Zhang, Xin Dong, Chih-Chiang Chen
2019 A* conf
ASPLOS
H. T. Kung, Bradley McDanel, Sai Qian Zhang
2019 C conf
ISCAS
H. T. Kung, Bradley McDanel, Sai Qian Zhang, C. T. Wang, Jin Cai, C. Y. Chen, Victor C. Y. Chang, M. F. Chen, Jack Yuan-Chen Sun, Douglas Yu
2018 conf
SPAWC
Sai Qian Zhang, Feng Xue, Nageen Himayat, Shilpa Talwar, H. T. Kung
2018 B conf
ICPR
H. T. Kung, Bradley McDanel, Sai Qian Zhang
2018 J jnl
CoRR
Miriam Cha, Youngjune L. Gwon, H. T. Kung
2018 Misc conf
ICASSP
Miriam Cha, Arjun Majumdar, H. T. Kung, Jarred Barber
2018 J jnl
CoRR
Sai Qian Zhang, H. T. Kung, Youngjune Gwon
2018 B conf
GLOBECOM
Marcus Z. Comiter, H. T. Kung
2018 conf
SiPS
H. T. Kung, Bradley McDanel, Sai Qian Zhang
2018 J jnl
CoRR
H. T. Kung, Bradley McDanel, Sai Qian Zhang
2017 B conf
GLOBECOM
Marcus Z. Comiter, Michael B. Crouse, H. T. Kung
2017 conf
MLSP
Miriam Cha, Youngjune Gwon, H. T. Kung
2017 J jnl
CoRR
Miriam Cha, Youngjune Gwon, H. T. Kung
2017 J jnl
CoRR
Surat Teerapittayanon, Bradley McDanel, H. T. Kung
2017 A conf
ICDCS
Surat Teerapittayanon, Bradley McDanel, H. T. Kung
2017 J jnl
CoRR
Surat Teerapittayanon, Bradley McDanel, H. T. Kung
2017 B conf
EWSN
Bradley McDanel, Surat Teerapittayanon, H. T. Kung
2017 J jnl
CoRR
Bradley McDanel, Surat Teerapittayanon, H. T. Kung
2017 C conf
ICMLA
Bradley McDanel, Surat Teerapittayanon, H. T. Kung
2017 J jnl
CoRR
Bradley McDanel, Surat Teerapittayanon, H. T. Kung
2017 Misc conf
ICASSP
Philippe Tillet, H. T. Kung, David D. Cox
2017 A conf
CIKM
Miriam Cha, Youngjune Gwon, H. T. Kung
2017 J jnl
CoRR
Miriam Cha, Youngjune Gwon, H. T. Kung
2017 conf
GLOBECOM Workshops
Marcus Z. Comiter, Michael B. Crouse, H. T. Kung, Jenn-Hwan Tarng, Zuo-Min Tsai, Wei-Ting Wu, Ta-Sung Lee, M.-C. Frank Chang, Yen-Cheng Kuan
2017 conf
ICC
Hsieh-Chung Chen, H. T. Kung, Marcus Z. Comiter
2016 B conf
GLOBECOM
Youngjune Gwon, Siamak Dastangoo, H. T. Kung, Carl Fossa
2016 B conf
ICPR
Surat Teerapittayanon, Bradley McDanel, H. T. Kung
2016 J jnl
IEEE Trans. Cogn. Commun. Netw.
Siamak Dastangoo, Carl Fossa, Youngjune L. Gwon, H. T. Kung
2016 B conf
ICPR
Youngjune Gwon, Miriam Cha, H. T. Kung
2016 conf
AVEC@ACM Multimedia
James R. Williamson, Elizabeth Godoy, Miriam Cha, Adrianne Schwarzentruber, Pooya Khorrami, Youngjune Gwon, H. T. Kung, Charlie K. Dagli, Thomas F. Quatieri
2016 B conf
ICPR
Marcus Z. Comiter, Miriam Cha, H. T. Kung, Surat Teerapittayanon
2016 A conf
INTERSPEECH
Youngjune L. Gwon, William M. Campbell, Douglas E. Sturim, H. T. Kung
2016 J jnl
CoRR
Youngjune Gwon, William M. Campbell, Kevin Brady, Douglas E. Sturim, Miriam Cha, H. T. Kung
2016 C conf
CloudCom
Michael B. Crouse, H. T. Kung
2016 conf
MLSP
Youngjune Gwon, Miriam Cha, William M. Campbell, H. T. Kung, Charlie K. Dagli
2015 conf
CTS
Hsieh-Chung Chen, Harnek Gulati, H. T. Kung, Surat Teerapittayanon
2015 B conf
GLOBECOM
Youngjune Gwon, Siamak Dastangoo, Carl Fossa, H. T. Kung
2015 A* conf
ACM Multimedia
Miriam Cha, Youngjune Gwon, H. T. Kung
2015 J jnl
CoRR
Miriam Cha, Youngjune Gwon, H. T. Kung
2015 conf
LCPC
H. T. Kung, Bradley McDanel, Surat Teerapittayanon
2015 conf
CVPR Workshops
Hsieh-Chung Chen, Marcus Z. Comiter, H. T. Kung, Bradley McDanel
2015 B conf
MobiHoc
Stephen J. Tarsa, Marcus Z. Comiter, Michael B. Crouse, Bradley McDanel, H. T. Kung
2015 A conf
ICWSM
Miriam Cha, Youngjune Gwon, H. T. Kung
2014 conf
ICAC
Michael B. Crouse, Kevin Chen, H. T. Kung
2014 conf
ICAC
Youngjune Gwon, H. T. Kung
2014 conf
HotCloud
Chit-Kwan Lin, H. T. Kung
2014 A* conf
ICML
Tsung-Han Lin, H. T. Kung
2014 conf
IOT
Ping-Heng Kuo, H. T. Kung
2014 conf
ICICDT
Stephen J. Tarsa, Amit P. Kumar, H. T. Kung
2013 conf
CNS
Youngjune Gwon, Siamak Dastangoo, Carl Fossa, H. T. Kung
2013 A* conf
INFOCOM
Tsung-Han Lin, H. T. Kung
2013 conf
MILCOM
Stephen J. Tarsa, H. T. Kung
2013 B conf
GLOBECOM
Youngjune Gwon, Siamak Dastangoo, H. T. Kung
2013 conf
HotPar
Tsung-Han Lin, Stephen J. Tarsa, H. T. Kung
2013 A* conf
INFOCOM
Youngjune Gwon, H. T. Kung
2013 conf
ICAC
Kevin Chen, H. T. Kung
2012 conf
SiPS
Yi-Min Tsai, Keng-Yen Huang, H. T. Kung, Dario Vlah, Youngjune Gwon, Liang-Gee Chen
2012 conf
IC3
H. T. Kung
2012 B conf
WCNC
Ping-Heng Kuo, H. T. Kung, Pangan Ting
2012 B conf
GLOBECOM
Tsung-Han Lin, H. T. Kung
2012 B conf
GLOBECOM
Youngjune Gwon, H. T. Kung, Dario Vlah
2012 conf
MILCOM
Hsieh-Chung Chen, Tsung-Han Lin, H. T. Kung, Chit-Kwan Lin, Youngjune Gwon
2012 conf
MILCOM
Stephen J. Tarsa, H. T. Kung
2012 J jnl
CoRR
H. T. Kung, Chia-Mu Yu
2012 C conf
ISCAS
Youngjune Gwon, H. T. Kung, Dario Vlah, Keng-Yen Huang, Yi-Min Tsai
2011 B conf
ICCCN
Chit-Kwan Lin, H. T. Kung, Tsung-Han Lin, Stephen J. Tarsa, Dario Vlah
2011 conf
HotCloud
H. T. Kung, Chit-Kwan Lin, Dario Vlah
2011 conf
MILCOM
Hsieh-Chung Chen, H. T. Kung, Dario Vlah, Daniel Hague, Michael Muccio, Brendon Poland
2011 conf
HotSec
Youngjune Gwon, H. T. Kung, Dario Vlah
2011 conf
MILCOM
Hsieh-Chung Chen, H. T. Kung, Dario Vlah, Bruce W. Suter
2011 conf
MILCOM
H. T. Kung, Stephen J. Tarsa
2011 B conf
ICCCN
Hsieh-Chung Chen, H. T. Kung
2010 J jnl
Int. J. Sens. Networks
H. T. Kung, Dario Vlah
2010 J jnl
CoRR
Richard P. Brent, Franklin T. Luk, H. T. Kung
2010 J jnl
Comput. Syst. Sci. Eng.
H. T. Kung, S. Y. Wang
2009 B conf
ICCCN
H. T. Kung, Dario Vlah
2009 A* conf
MobiCom
H. T. Kung, Chit-Kwan Lin, Tsung-Han Lin, Dario Vlah
2009 C conf
SEKE
H. T. Kung
2008 J jnl
IEEE Trans. Commun.
Oh-Soon Shin, H. T. Kung, Vahid Tarokh
2008 conf
CEC/EEE
Chia-Hsin Huang, H. T. Kung, Chia-Yung Su
2007 J jnl
EURASIP J. Adv. Signal Process.
H. T. Kung, Bruce Wilsey Suter
2007 J jnl
IEEE Trans. Veh. Technol.
Oh-Soon Shin, Albert M. Chan, H. T. Kung, Vahid Tarokh
2007 B conf
WCNC
Chen-Mou Cheng, Pai-Hsiang Hsiao, H. T. Kung, Dario Vlah
2007 C conf
WOWMOM
Chen-Mou Cheng, Pai-Hsiang Hsiao, H. T. Kung, Dario Vlah
2006 B conf
GLOBECOM
Chen-Mou Cheng, Pai-Hsiang Hsiao, H. T. Kung, Dario Vlah
2006 B conf
ICCCN
Chen-Mou Cheng, Pai-Hsiang Hsiao, H. T. Kung, Dario Vlah
2005 B conf
WCNC
Pai-Hsiang Hsiao, H. T. Kung
2004 conf
ISPAN
Pai-Hsiang Hsiao, H. T. Kung
2004 B conf
GLOBECOM
Chen-Mou Cheng, Yu-Sheng Huan, H. T. Kung, Chun-Hsin Wu
2003 A conf
ICWS
H. T. Kung, Feng Zhu, Marco Iansiti
2003 conf
DISCEX (2)
Chen-Mou Cheng, H. T. Kung, Koan-Sin Tan, Scott O. Bradner
2003 conf
DISCEX (1)
H. T. Kung, Chen-Mou Cheng, Koan-Sin Tan, Scott O. Bradner
2003 B conf
WCNC
H. T. Kung, Dario Vlah
2003 J jnl
Comput. Commun.
H. T. Kung, Koan-Sin Tan, Pai-Hsiang Hsiao
2002 J jnl
Comput. Networks
Shie Yuan Wang, H. T. Kung
2002 C conf
ISCC
H. T. Kung, Koan-Sin Tan, Pai-Hsiang Hsiao
2002 B conf
GLOBECOM
Chen-Mou Cheng, H. T. Kung, Koan-Sin Tan
2001 B conf
GLOBECOM
Raquel Hill, H. T. Kung
2001 B conf
GLOBECOM
Pai-Hsiang Hsiao, H. T. Kung, Koan-Sin Tan
2001 B conf
MobiHoc
Zong Da Chen, H. T. Kung, Dario Vlah
2001 A* conf
INFOCOM
Pai-Hsiang Hsiao, Adon Hwang, H. T. Kung, Dario Vlah
2001 conf
SIIT
Mark Gaynor, Scott O. Bradner, Marco Iansiti, H. T. Kung
2001 J jnl
Wirel. Networks
Shie Yuan Wang, H. T. Kung
2001 B conf
NOSSDAV
Pai-Hsiang Hsiao, H. T. Kung, Koan-Sin Tan
2000 A* conf
MobiCom
Brad Karp, H. T. Kung
1999 A* conf
INFOCOM
Shie Yuan Wang, H. T. Kung
1999 Misc conf
PDPTA
H. T. Kung, Shie Yuan Wang
1999 B conf
ICNP
H. T. Kung, Shie Yuan Wang
1998 J jnl
IEEE Commun. Mag.
Alan Chapman, H. T. Kung
1998 A* conf
INFOCOM
Dong Lin, H. T. Kung
1998 J jnl
CoRR
H. T. Kung, S. Y. Wang
1998 conf
25 Years ISCA: Retrospectives and Reprints
Marco Annaratone, Emmanuel A. Arnould, Thomas R. Gross, H. T. Kung, Monica S. Lam, Onat Menzilcioglu, Ken Sarocky, Jon A. Webb
1998 A* conf
INFOCOM
H. T. Kung, Shie Yuan Wang
1997 A* conf
INFOCOM
H. T. Kung, Shie Yuan Wang
1997 A* conf
INFOCOM
Koling Chang, Robert Morris, H. T. Kung
1995 J jnl
IEEE Netw.
H. T. Kung, Robert Morris
1995 A* conf
INFOCOM
H. T. Kung, Koling Chang
1994 A* conf
SIGCOMM
H. T. Kung, Trevor Blackwell, Alan Chapman
1994 conf
USENIX Summer
Trevor Blackwell, Kee Chan, Koling Chang, Thomas Charuhas, James Gwertzman, Brad Karp, H. T. Kung, David Li, Dong Lin, Robert Morris, Rob Polansky, Diane Tang, Cliff Young, John Zao
1993 A conf
HPDC
H. T. Kung
1993 B conf
ICNP
H. T. Kung, Alan Chapman
1992 conf
HPN
Peter Steenkiste, Brian Zill, H. T. Kung, Steven Schlick, Jim Hughes, Bob Kowalski, John Mullaney
1992 J jnl
IEEE Commun. Mag.
H. T. Kung
1991 A conf
SC
H. T. Kung, Jaspal Subhlok
1991 A* conf
FOCS
I-Chen Wu, H. T. Kung
1991 A conf
SC
H. T. Kung, Robert D. Sansom, Steven Schlick, Peter Steenkiste, Matthieu Arnould, Francois J. Bitz, Fred Christianson, Eric C. Cooper, Onat Menzilcioglu, Denise Ombres, Brian Zill
1991 B conf
PPoPP
H. T. Kung, Peter Steenkiste, Marco Dimas Gubitoso, Manpreet Khaira
1990 conf
ASAP
Brent Baxter, George W. Cox, Thomas R. Gross, H. T. Kung, David R. O'Hallaron, Craig Peterson, Jon A. Webb, Paul Wiley
1990 conf
Compcon
H. T. Kung
1990 A* conf
ISCA
Shekhar Borkar, Robert Cohn, George W. Cox, Thomas R. Gross, H. T. Kung, Monica Lam, Margie Levine, Brian Moore, Wire Moore, Craig Peterson, Jim Susman, Jim Sutton, John Urbanski, Jon A. Webb
1990 J jnl
Microprocess. Microsystems
H. T. Kung
1989 conf
FTCS
Onat Menzilcioglu, H. T. Kung, Siang Wun Song
1989 A* conf
ASPLOS
Emmanuel A. Arnould, Francois J. Bitz, Eric C. Cooper, H. T. Kung, Robert D. Sansom, Peter Steenkiste
1988 A* conf
ISCA
H. T. Kung
1988 J jnl
J. Complex.
H. T. Kung
1988 conf
ICNN
Dean A. Pomerleau, George L. Gusciora, David S. Touretzky, H. T. Kung
1988 A conf
ICS
H. T. Kung
1987 conf
COMPCON
Marco Annaratone, Francois J. Bitz, Ed Clune, H. T. Kung, Prabir C. Maulik, Hudson Benedito Ribas, P. S. Tseng, Jon A. Webb
1987 conf
COMPCON
Marco Annaratone, Emmanuel A. Arnould, Robert Cohn, Thomas R. Gross, H. T. Kung, Monica S. Lam, Onat Menzilcioglu, Ken Sarocky, John Senko, Jon A. Webb
1987 J jnl
IEEE Trans. Computers
Marco Annaratone, Emmanuel A. Arnould, Thomas R. Gross, H. T. Kung, Monica Lam, Onat Menzilcioglu, Jon A. Webb
1986 J jnl
Distributed Comput.
H. T. Kung, Jon A. Webb
1986 A* conf
ISCA
H. T. Kung
1986 conf
IFIP Congress
H. T. Kung
1986 Misc conf
ICASSP
Marco Annaratone, Emmanuel A. Arnould, H. T. Kung, Onat Menzilcioglu
1986 A* conf
ISCA
Marco Annaratone, Emmanuel A. Arnould, Thomas R. Gross, H. T. Kung, Monica S. Lam, Onat Menzilcioglu, Ken Sarocky, Jon A. Webb
1985 Misc conf
ICASSP
Emmanuel A. Arnould, H. T. Kung, Onat Menzilcioglu, Ken Sarocky
1985 J jnl
J. Complex.
H. T. Kung
1985 J jnl
IEEE Trans. Computers
Allan L. Fisher, H. T. Kung
1985 A* conf
ICRA
Thomas R. Gross, H. T. Kung, Monica Lam, Jon A. Webb
1984 conf
AFIPS National Computer Conference
M. Sugie, Onat Menzilcioglu, H. T. Kung
1984 conf
VLSI Engineering
H. T. Kung
1984 J jnl
IEEE Trans. Computers
Richard P. Brent, H. T. Kung
1984 J jnl
J. Parallel Distributed Comput.
H. T. Kung, Monica S. Lam
1983 J jnl
Acta Informatica
H. T. Kung, Christos H. Papadimitriou
1983 A* conf
ISCA
Allan L. Fisher, H. T. Kung, Louis Monier, Yasunori Dohi
1983 conf
IFIP Congress
Richard P. Brent, H. T. Kung, Franklin T. Luk
1983 A* conf
ISCA
Allan L. Fisher, H. T. Kung
1983 J jnl
Image Vis. Comput.
H. T. Kung, Lawrence M. Ruane, David W. L. Yen
1983 conf
ACM Conference on Computer Science
H. T. Kung
1982 J jnl
IEEE Trans. Computers
Richard P. Brent, H. T. Kung
1982 J jnl
J. ACM
Richard P. Brent, H. T. Kung
1982 A conf
RTSS
Roberto Bisiani, Michael J. Foster, H. T. Kung, Kemal Oflazer
1982 J jnl
Computer
H. T. Kung
1981 A* conf
STOC
Jia-Wei Hong, H. T. Kung
1981 J jnl
ACM Trans. Database Syst.
H. T. Kung, John T. Robinson
1981 J jnl
J. ACM
Richard P. Brent, H. T. Kung
1981 conf
SYMSACC
H. T. Kung
1980 J jnl
ACM Trans. Database Syst.
H. T. Kung, Philip L. Lehman
1980 A* conf
ISCA
Michael J. Foster, H. T. Kung
1980 J jnl
Inf. Process. Lett.
Richard P. Brent, H. T. Kung
1980 J jnl
Aust. Comput. J.
Gérard M. Baudet, Richard P. Brent, H. T. Kung
1980 conf
SIGMOD Conference
H. T. Kung, Philip L. Lehman
1980 A* conf
STOC
Richard P. Brent, H. T. Kung
1980 J jnl
Computer
Michael J. Foster, H. T. Kung
1980 J jnl
Adv. Comput.
H. T. Kung
1979 conf
SIGMOD Conference
H. T. Kung, Christos H. Papadimitriou
1979 A* conf
FOCS
Mihalis Yannakakis, Christos H. Papadimitriou, H. T. Kung
1979 A* conf
VLDB
H. T. Kung, John T. Robinson
1978 A* conf
VLDB
H. T. Kung, Philip L. Lehman
1978 J jnl
J. ACM
H. T. Kung, Joseph F. Traub
1978 J jnl
J. ACM
Richard P. Brent, H. T. Kung
1978 J jnl
J. ACM
Jon Louis Bentley, H. T. Kung, Mario Schkolnick, Clark D. Thompson
1977 A* conf
FOCS
H. T. Kung, S. W. Song
1977 J jnl
SIAM J. Comput.
H. T. Kung, D. M. Tong
1977 J jnl
Commun. ACM
Clark D. Thompson, H. T. Kung
1977 J jnl
J. ACM
Laurent Hyafil, H. T. Kung
1976 J jnl
J. ACM
H. T. Kung
1976 A* conf
STOC
Clark D. Thompson, H. T. Kung
1975 J jnl
J. ACM
H. T. Kung, Fabrizio Luccio, Franco P. Preparata
1975 A* conf
STOC
Laurent Hyafil, H. T. Kung
1974 A* conf
STOC
H. T. Kung
1974 conf
SWAT
H. T. Kung
1974 J jnl
J. ACM
H. T. Kung, Joseph F. Traub
1973 J jnl
J. Comput. Syst. Sci.
H. T. Kung
1973 J jnl
Inf. Process. Lett.
H. T. Kung
1973 A* conf
STOC
H. T. Kung
1972 A* conf
STOC
H. T. Kung
tests/unit/test_apk_code_analyzer.py
← Index tests/unit/test_apk_code_analyzer.py python
"""
Unit tests for APK code analysis components.

Tests APKCodeAnalyzer, LibraryFilter, SmaliParser, method enumeration,
library filtering, and method key matching. All external tools are mocked.
"""
import os
import tempfile
import textwrap

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

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


def _has_mmh3():
    try:
        import mmh3  # noqa: F401
        return True
    except ImportError:
        return False


# ============================================================================
# LibraryFilter Tests
# ============================================================================

class TestLibraryFilter:
    """Tests for package-based library filtering."""

    def test_default_prefixes_loaded(self):
        from redb.extractors.decompiler.apk.library_filter import LibraryFilter
        lf = LibraryFilter()
        assert lf.is_library("android.app.Activity")
        assert lf.is_library("androidx.core.app.NotificationCompat")

    def test_user_class_not_filtered(self):
        from redb.extractors.decompiler.apk.library_filter import LibraryFilter
        lf = LibraryFilter()
        assert not lf.is_library("com.example.myapp.MainActivity")
        assert not lf.is_library("org.myorg.MyClass")

    def test_dalvik_descriptor_format(self):
        from redb.extractors.decompiler.apk.library_filter import LibraryFilter
        lf = LibraryFilter()
        assert lf.is_library("Landroid/app/Activity;")
        assert lf.is_library("Landroidx/core/app/NotificationCompat;")
        assert not lf.is_library("Lcom/example/myapp/MainActivity;")

    def test_custom_prefixes(self):
        from redb.extractors.decompiler.apk.library_filter import LibraryFilter
        lf = LibraryFilter(prefixes=["com.custom."])
        assert lf.is_library("com.custom.SomeClass")
        assert not lf.is_library("android.app.Activity")

    def test_env_var_override(self):
        from redb.extractors.decompiler.apk.library_filter import LibraryFilter
        with patch.dict(os.environ, {"APK_LIBRARY_PREFIXES": "my.lib.,other.lib."}):
            lf = LibraryFilter()
            assert lf.is_library("my.lib.SomeClass")
            assert lf.is_library("other.lib.AnotherClass")
            assert not lf.is_library("android.app.Activity")

    def test_filter_stats(self):
        from redb.extractors.decompiler.apk.library_filter import LibraryFilter
        lf = LibraryFilter()
        lf.is_library("android.app.Activity")
        lf.is_library("com.example.MyClass")
        lf.is_library("kotlin.Unit")
        stats = lf.get_filter_stats()
        assert stats["library"] == 2
        assert stats["user"] == 1

    def test_normalize_class_name(self):
        from redb.extractors.decompiler.apk.library_filter import LibraryFilter
        assert LibraryFilter._normalize_class_name("Lcom/example/Foo;") == "com.example.Foo"
        assert LibraryFilter._normalize_class_name("com.example.Foo") == "com.example.Foo"
        assert LibraryFilter._normalize_class_name("com/example/Foo") == "com.example.Foo"

    def test_google_libraries_filtered(self):
        from redb.extractors.decompiler.apk.library_filter import LibraryFilter
        lf = LibraryFilter()
        assert lf.is_library("com.google.android.gms.ads.AdView")
        assert lf.is_library("com.google.firebase.messaging.FirebaseMessagingService")
        assert lf.is_library("com.google.gson.Gson")

    def test_kotlin_filtered(self):
        from redb.extractors.decompiler.apk.library_filter import LibraryFilter
        lf = LibraryFilter()
        assert lf.is_library("kotlin.Unit")
        assert lf.is_library("kotlinx.coroutines.CoroutineScope")

    def test_third_party_libs_filtered(self):
        from redb.extractors.decompiler.apk.library_filter import LibraryFilter
        lf = LibraryFilter()
        assert lf.is_library("com.squareup.okhttp3.OkHttpClient")
        assert lf.is_library("io.reactivex.Observable")
        assert lf.is_library("org.apache.commons.io.IOUtils")

    def test_empty_class_name(self):
        from redb.extractors.decompiler.apk.library_filter import LibraryFilter
        lf = LibraryFilter()
        assert not lf.is_library("")


# ============================================================================
# SmaliParser Tests
# ============================================================================

class TestSmaliParser:
    """Tests for smali file parsing."""

    SAMPLE_SMALI = textwrap.dedent("""\
        .class public Lcom/example/MyClass;
        .super Ljava/lang/Object;

        .method public constructor <init>()V
            .registers 1
            invoke-direct {p0}, Ljava/lang/Object;-><init>()V
            return-void
        .end method

        .method public onCreate(Landroid/os/Bundle;)V
            .registers 4
            .param p1, "savedInstanceState"

            .line 10
            invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
            const/high16 v0, 0x7f090000
            invoke-virtual {p0, v0}, Lcom/example/MyClass;->setContentView(I)V
            const-string v1, "hello"
            invoke-virtual {p0, v1}, Lcom/example/MyClass;->log(Ljava/lang/String;)V
            return-void
        .end method

        .method public abstract doSomething()V
        .end method

        .method public native nativeMethod()V
        .end method
    """)

    def test_parse_smali_content(self):
        from redb.extractors.decompiler.apk.smali_parser import SmaliParser
        methods = SmaliParser._parse_smali_content(self.SAMPLE_SMALI)
        # abstract and native should be skipped
        assert len(methods) == 2

    def test_method_names_extracted(self):
        from redb.extractors.decompiler.apk.smali_parser import SmaliParser
        methods = SmaliParser._parse_smali_content(self.SAMPLE_SMALI)
        names = {m.method_name for m in methods}
        assert "<init>" in names
        assert "onCreate" in names

    def test_class_name_extracted(self):
        from redb.extractors.decompiler.apk.smali_parser import SmaliParser
        methods = SmaliParser._parse_smali_content(self.SAMPLE_SMALI)
        for m in methods:
            assert m.class_name == "Lcom/example/MyClass;"

    def test_method_signature(self):
        from redb.extractors.decompiler.apk.smali_parser import SmaliParser
        methods = SmaliParser._parse_smali_content(self.SAMPLE_SMALI)
        oncreate = [m for m in methods if m.method_name == "onCreate"][0]
        assert oncreate.method_signature == "(Landroid/os/Bundle;)V"

    def test_instruction_count(self):
        from redb.extractors.decompiler.apk.smali_parser import SmaliParser
        methods = SmaliParser._parse_smali_content(self.SAMPLE_SMALI)
        oncreate = [m for m in methods if m.method_name == "onCreate"][0]
        # invoke-super, const/high16, invoke-virtual, const-string, invoke-virtual, return-void
        assert oncreate.instruction_count == 6

    def test_register_count(self):
        from redb.extractors.decompiler.apk.smali_parser import SmaliParser
        methods = SmaliParser._parse_smali_content(self.SAMPLE_SMALI)
        oncreate = [m for m in methods if m.method_name == "onCreate"][0]
        assert oncreate.register_count == 4

    def test_register_count_locals_directive(self):
        """apktool outputs .locals by default, not .registers."""
        from redb.extractors.decompiler.apk.smali_parser import SmaliParser
        smali_with_locals = textwrap.dedent("""\
            .class public Lcom/example/Locals;
            .super Ljava/lang/Object;

            .method public doWork()V
                .locals 3
                const/4 v0, 0x0
                const/4 v1, 0x1
                add-int v2, v0, v1
                return-void
            .end method
        """)
        methods = SmaliParser._parse_smali_content(smali_with_locals)
        assert len(methods) == 1
        assert methods[0].register_count == 3

    def test_abstract_native_skipped(self):
        from redb.extractors.decompiler.apk.smali_parser import SmaliParser
        methods = SmaliParser._parse_smali_content(self.SAMPLE_SMALI)
        names = {m.method_name for m in methods}
        assert "doSomething" not in names
        assert "nativeMethod" not in names

    def test_normalize_smali_body(self):
        from redb.extractors.decompiler.apk.smali_parser import SmaliParser
        body = textwrap.dedent("""\
            .registers 4
            .line 10
            # comment
            invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V

            const-string v1, "hello"
        """)
        normalized = SmaliParser.normalize_smali_body(body)
        assert ".line" not in normalized
        assert "# comment" not in normalized
        assert "invoke-super" in normalized
        assert "const-string" in normalized

    def test_count_instructions(self):
        from redb.extractors.decompiler.apk.smali_parser import SmaliParser
        body = textwrap.dedent("""\
            .registers 4
            .param p1, "x"
            invoke-virtual {p0}, Lcom/example/Foo;->bar()V
            const/4 v0, 0x0
            :label_0
            if-eqz v0, :label_1
            return-void
            :label_1
            goto :label_0
        """)
        assert SmaliParser.count_instructions(body) == 5

    def test_make_method_key(self):
        from redb.extractors.decompiler.apk.smali_parser import SmaliParser
        key = SmaliParser.make_method_key(
            "Lcom/example/Foo;", "bar", "(I)V"
        )
        assert key == "Lcom/example/Foo;->bar(I)V"

    def test_parse_smali_file(self):
        from redb.extractors.decompiler.apk.smali_parser import SmaliParser
        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".smali", delete=False
        ) as f:
            f.write(self.SAMPLE_SMALI)
            f.flush()
            try:
                methods = SmaliParser.parse_smali_file(f.name)
                assert len(methods) == 2
            finally:
                os.unlink(f.name)

    def test_parse_smali_directory(self):
        from redb.extractors.decompiler.apk.smali_parser import SmaliParser
        with tempfile.TemporaryDirectory() as tmpdir:
            # Create nested dir structure
            pkg_dir = os.path.join(tmpdir, "com", "example")
            os.makedirs(pkg_dir)
            with open(os.path.join(pkg_dir, "MyClass.smali"), "w") as f:
                f.write(self.SAMPLE_SMALI)

            result = SmaliParser.parse_smali_directory(tmpdir)
            assert len(result) == 2
            # Check keys are in expected format
            for key in result:
                assert "->" in key

    def test_empty_smali_file(self):
        from redb.extractors.decompiler.apk.smali_parser import SmaliParser
        methods = SmaliParser._parse_smali_content("")
        assert methods == []

    def test_class_only_no_methods(self):
        from redb.extractors.decompiler.apk.smali_parser import SmaliParser
        content = ".class public Lcom/example/Empty;\n.super Ljava/lang/Object;\n"
        methods = SmaliParser._parse_smali_content(content)
        assert methods == []


# ============================================================================
# MethodExtractor Tests (Hashing, Obfuscation, Type Conversion)
# ============================================================================

class TestMethodExtractor:
    """Tests for method-level content extraction and hashing."""

    def test_compute_sha256(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_sha256
        h = compute_sha256("test content")
        assert len(h) == 64
        assert h == compute_sha256("test content")  # deterministic

    def test_compute_sha256_different_input(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_sha256
        assert compute_sha256("a") != compute_sha256("b")

    def test_compute_ssdeep_short_input(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_ssdeep
        result = compute_ssdeep("short")
        assert result is None

    def test_compute_ssdeep_long_input(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_ssdeep
        result = compute_ssdeep("x" * 200)
        # May be None depending on entropy, but shouldn't crash
        assert result is None or isinstance(result, str)

    def test_compute_tlsh_short_input(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_tlsh
        result = compute_tlsh("short")
        assert result is None

    def test_compute_tlsh_long_input(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_tlsh
        data = "".join(chr(i % 256) for i in range(200))
        result = compute_tlsh(data)
        assert result is None or isinstance(result, str)

    def test_compute_minhash_returns_none_without_mmh3(self):
        from unittest.mock import patch
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        with patch.dict("sys.modules", {"mmh3": None}):
            # Force reimport to hit ImportError
            import importlib
            import redb.extractors.decompiler.apk.method_extractor as mod
            importlib.reload(mod)
            result = mod.compute_minhash("line1\nline2\nline3\nline4")
            # mmh3 may or may not be available; just check it doesn't crash
            assert result is None or isinstance(result, list)
            importlib.reload(mod)  # restore

    def test_compute_minhash_too_few_lines(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        result = compute_minhash("invoke-direct {v0}, Lfoo;->bar()V")
        # Only 1 instruction line, need at least 3 for 3-grams
        assert result is None

    @pytest.mark.skipif(
        not _has_mmh3(), reason="mmh3 not installed"
    )
    def test_compute_minhash_deterministic(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        smali = (
            "invoke-direct {v1}, Ljava/lang/Object;-><init>()V\n"
            "const-string v0, \"hello\"\n"
            "iput-object v0, v1, LA;->a:Ljava/lang/String;\n"
            "return-void"
        )
        sig1 = compute_minhash(smali)
        sig2 = compute_minhash(smali)
        assert sig1 is not None
        assert sig1 == sig2

    @pytest.mark.skipif(
        not _has_mmh3(), reason="mmh3 not installed"
    )
    def test_compute_minhash_signature_length(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        smali = (
            "invoke-direct {v1}, Ljava/lang/Object;-><init>()V\n"
            "const-string v0, \"hello\"\n"
            "iput-object v0, v1, LA;->a:Ljava/lang/String;\n"
            "return-void"
        )
        sig = compute_minhash(smali)
        assert sig is not None
        assert len(sig) == 64  # SIGNATURE_LENGTH

    @pytest.mark.skipif(
        not _has_mmh3(), reason="mmh3 not installed"
    )
    def test_compute_minhash_value_range(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        smali = (
            "invoke-direct {v1}, Ljava/lang/Object;-><init>()V\n"
            "const-string v0, \"hello\"\n"
            "iput-object v0, v1, LA;->a:Ljava/lang/String;\n"
            "return-void"
        )
        sig = compute_minhash(smali)
        assert sig is not None
        for val in sig:
            assert 0 <= val < 256  # 8-bit values

    @pytest.mark.skipif(
        not _has_mmh3(), reason="mmh3 not installed"
    )
    def test_compute_minhash_different_inputs_differ(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        smali_a = (
            "invoke-direct {v1}, Ljava/lang/Object;-><init>()V\n"
            "const-string v0, \"hello\"\n"
            "iput-object v0, v1, LA;->a:Ljava/lang/String;\n"
            "return-void"
        )
        smali_b = (
            "sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;\n"
            "const-string v1, \"world\"\n"
            "invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V\n"
            "return-void"
        )
        sig_a = compute_minhash(smali_a)
        sig_b = compute_minhash(smali_b)
        assert sig_a is not None
        assert sig_b is not None
        assert sig_a != sig_b

    @pytest.mark.skipif(
        not _has_mmh3(), reason="mmh3 not installed"
    )
    def test_compute_minhash_skips_directives_and_labels(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        # Directives and labels should be filtered out
        smali = (
            ".registers 3\n"
            ":start\n"
            "invoke-direct {v1}, Ljava/lang/Object;-><init>()V\n"
            ".line 10\n"
            "const-string v0, \"hello\"\n"
            "iput-object v0, v1, LA;->a:Ljava/lang/String;\n"
            "return-void"
        )
        smali_clean = (
            "invoke-direct {v1}, Ljava/lang/Object;-><init>()V\n"
            "const-string v0, \"hello\"\n"
            "iput-object v0, v1, LA;->a:Ljava/lang/String;\n"
            "return-void"
        )
        sig_with_directives = compute_minhash(smali)
        sig_clean = compute_minhash(smali_clean)
        assert sig_with_directives == sig_clean

    def test_dalvik_to_java_class(self):
        from redb.extractors.decompiler.apk.method_extractor import dalvik_to_java_class
        assert dalvik_to_java_class("Lcom/example/Foo;") == "com.example.Foo"
        assert dalvik_to_java_class("com.example.Foo") == "com.example.Foo"

    def test_dalvik_type_to_java(self):
        from redb.extractors.decompiler.apk.method_extractor import dalvik_type_to_java
        assert dalvik_type_to_java("V") == "void"
        assert dalvik_type_to_java("I") == "int"
        assert dalvik_type_to_java("Z") == "boolean"
        assert dalvik_type_to_java("Ljava/lang/String;") == "String"
        assert dalvik_type_to_java("[I") == "int[]"
        assert dalvik_type_to_java("[Ljava/lang/String;") == "String[]"

    def test_dalvik_to_java_prototype(self):
        from redb.extractors.decompiler.apk.method_extractor import dalvik_to_java_prototype
        result = dalvik_to_java_prototype("onCreate", "(Landroid/os/Bundle;)V")
        assert result == "void onCreate(Bundle)"

    def test_dalvik_to_java_prototype_no_params(self):
        from redb.extractors.decompiler.apk.method_extractor import dalvik_to_java_prototype
        result = dalvik_to_java_prototype("toString", "()Ljava/lang/String;")
        assert result == "String toString()"

    def test_dalvik_to_java_prototype_multiple_params(self):
        from redb.extractors.decompiler.apk.method_extractor import dalvik_to_java_prototype
        result = dalvik_to_java_prototype("foo", "(ILjava/lang/String;Z)V")
        assert result == "void foo(int, String, boolean)"

    def test_detect_obfuscation_short_name(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        result = detect_obfuscation_indicators("a", "Lcom/example/Foo;", "", 10)
        assert result["short_method_name"] is True
        result = detect_obfuscation_indicators("onCreate", "Lcom/example/Foo;", "", 10)
        assert result["short_method_name"] is False

    def test_detect_obfuscation_short_class(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        result = detect_obfuscation_indicators("foo", "Lcom/example/a;", "", 10)
        assert result["short_class_name"] is True
        result = detect_obfuscation_indicators("foo", "Lcom/example/MainActivity;", "", 10)
        assert result["short_class_name"] is False

    def test_detect_reflection_calls(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        smali = "invoke-virtual {v0}, Ljava/lang/reflect/Method;->invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
        result = detect_obfuscation_indicators("foo", "Lcom/Foo;", smali, 10)
        assert result["has_reflection_calls"] is True

    def test_detect_no_reflection(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        smali = "invoke-virtual {p0}, Lcom/example/Foo;->bar()V"
        result = detect_obfuscation_indicators("foo", "Lcom/Foo;", smali, 10)
        assert result["has_reflection_calls"] is False

    def test_detect_string_encryption(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        smali = 'const-string v0, "encrypted"\n    invoke-static {v0}, Lcom/example/Crypto;->decrypt(Ljava/lang/String;)Ljava/lang/String;'
        result = detect_obfuscation_indicators("foo", "Lcom/Foo;", smali, 10)
        assert result["has_string_encryption"] is True

    def test_detect_excessive_goto(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        smali = "\n".join(["goto :label_0"] * 20)
        result = detect_obfuscation_indicators("foo", "Lcom/Foo;", smali, 30)
        # threshold = max(5, 30*0.15) = 5, 20 > 5
        assert result["excessive_goto_count"] is True

    def test_detect_no_excessive_goto(self):
        from redb.extractors.decompiler.apk.method_extractor import detect_obfuscation_indicators
        smali = "goto :label_0\nreturn-void"
        result = detect_obfuscation_indicators("foo", "Lcom/Foo;", smali, 100)
        assert result["excessive_goto_count"] is False

    def test_parse_dalvik_params_empty(self):
        from redb.extractors.decompiler.apk.method_extractor import _parse_dalvik_params
        assert _parse_dalvik_params("") == []

    def test_parse_dalvik_params_primitives(self):
        from redb.extractors.decompiler.apk.method_extractor import _parse_dalvik_params
        result = _parse_dalvik_params("IZJ")
        assert result == ["I", "Z", "J"]

    def test_parse_dalvik_params_object(self):
        from redb.extractors.decompiler.apk.method_extractor import _parse_dalvik_params
        result = _parse_dalvik_params("Ljava/lang/String;")
        assert result == ["Ljava/lang/String;"]

    def test_parse_dalvik_params_mixed(self):
        from redb.extractors.decompiler.apk.method_extractor import _parse_dalvik_params
        result = _parse_dalvik_params("ILjava/lang/String;Z")
        assert result == ["I", "Ljava/lang/String;", "Z"]

    def test_parse_dalvik_params_array(self):
        from redb.extractors.decompiler.apk.method_extractor import _parse_dalvik_params
        result = _parse_dalvik_params("[I[Ljava/lang/String;")
        assert result == ["[I", "[Ljava/lang/String;"]


# ============================================================================
# APKCodeAnalyzer Tests (mocked tools)
# ============================================================================

class TestAPKCodeAnalyzer:
    """Tests for the APKCodeAnalyzer orchestration."""

    def test_init_defaults(self):
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer
        analyzer = APKCodeAnalyzer("/fake/path.apk")
        assert analyzer.filepath == "/fake/path.apk"
        assert analyzer.timeout == 600
        assert analyzer.min_instructions == 5

    def test_init_custom_timeout(self):
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer
        analyzer = APKCodeAnalyzer("/fake/path.apk", timeout=300)
        assert analyzer.timeout == 300

    def test_init_min_instructions_env(self):
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer
        with patch.dict(os.environ, {"APK_MIN_METHOD_INSTRUCTIONS": "10"}):
            analyzer = APKCodeAnalyzer("/fake/path.apk")
            assert analyzer.min_instructions == 10

    @patch("redb.extractors.decompiler.apk.analyzer.APKCodeAnalyzer._run_androguard")
    @patch.object(
        __import__("redb.extractors.decompiler.apk.apktool_wrapper", fromlist=["ApktoolDisassembler"]).ApktoolDisassembler,
        "disassemble",
        return_value=False,
    )
    @patch.object(
        __import__("redb.extractors.decompiler.apk.jadx_wrapper", fromlist=["JADXDecompiler"]).JADXDecompiler,
        "decompile",
        return_value=False,
    )
    def test_extract_returns_dict_keys(self, mock_jadx, mock_apktool, mock_androguard):
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer
        mock_analysis = MagicMock()
        mock_analysis.get_methods.return_value = []
        mock_androguard.return_value = (MagicMock(), [], mock_analysis)

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

        assert "decompiled_content" in results
        assert "decompiled_refs" in results
        assert "smali_content" in results
        assert "smali_refs" in results
        assert "similarity_metrics" in results
        assert "strings" in results
        assert "analysis_errors" in results
        analyzer.cleanup()

    @patch("redb.extractors.decompiler.apk.analyzer.APKCodeAnalyzer._run_androguard")
    def test_extract_androguard_failure(self, mock_androguard):
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer
        mock_androguard.side_effect = Exception("Analysis failed")

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

        assert len(results["analysis_errors"]) > 0
        analyzer.cleanup()

    def test_cleanup_removes_temp_dirs(self):
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer
        analyzer = APKCodeAnalyzer("/fake/path.apk")
        tmpdir = tempfile.mkdtemp()
        analyzer._temp_dirs.append(tmpdir)
        assert os.path.isdir(tmpdir)
        analyzer.cleanup()
        assert not os.path.isdir(tmpdir)

    def test_normalize_java(self):
        from redb.extractors.decompiler.apk.analyzer import _normalize_java
        source = "  public void foo() {\n    int x = 1;\n  }\n"
        normalized = _normalize_java(source)
        assert normalized == "public void foo() {\nint x = 1;\n}"


class TestNormalizeAndroguardOperands:
    """Tests for androguard-to-apktool output normalization."""

    def test_invoke_adds_braces(self):
        from redb.extractors.decompiler.apk.analyzer import _normalize_androguard_operands
        result = _normalize_androguard_operands(
            "invoke-direct",
            "v1, Ljava/lang/Object;-><init>()V"
        )
        assert result == "{v1}, Ljava/lang/Object;-><init>()V"

    def test_invoke_virtual_multiple_regs(self):
        from redb.extractors.decompiler.apk.analyzer import _normalize_androguard_operands
        result = _normalize_androguard_operands(
            "invoke-virtual",
            "v0, v1, Ljava/lang/String;->equals(Ljava/lang/Object;)Z"
        )
        assert result == "{v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z"

    def test_invoke_static_no_regs(self):
        from redb.extractors.decompiler.apk.analyzer import _normalize_androguard_operands
        # invoke-static with no register args (rare but possible)
        result = _normalize_androguard_operands(
            "invoke-static",
            "Ljava/lang/System;->gc()V"
        )
        # First part starts with L, so no registers to wrap
        assert result == "Ljava/lang/System;->gc()V"

    def test_invoke_range(self):
        from redb.extractors.decompiler.apk.analyzer import _normalize_androguard_operands
        result = _normalize_androguard_operands(
            "invoke-virtual/range",
            "v3, v4, v5, Landroid/util/Log;->d(Ljava/lang/String; Ljava/lang/String;)I"
        )
        assert result == "{v3, v4, v5}, Landroid/util/Log;->d(Ljava/lang/String; Ljava/lang/String;)I"

    def test_iget_field_colon(self):
        from redb.extractors.decompiler.apk.analyzer import _normalize_androguard_operands
        result = _normalize_androguard_operands(
            "iget-object",
            "v0, v4, LF;->a Ljava/lang/String;"
        )
        assert result == "v0, v4, LF;->a:Ljava/lang/String;"

    def test_iput_field_colon(self):
        from redb.extractors.decompiler.apk.analyzer import _normalize_androguard_operands
        result = _normalize_androguard_operands(
            "iput-object",
            "v0, v1, LA;->b Ljava/lang/String;"
        )
        assert result == "v0, v1, LA;->b:Ljava/lang/String;"

    def test_sget_primitive_field(self):
        from redb.extractors.decompiler.apk.analyzer import _normalize_androguard_operands
        result = _normalize_androguard_operands(
            "sget",
            "v0, Lcom/Foo;->count I"
        )
        assert result == "v0, Lcom/Foo;->count:I"

    def test_sput_array_field(self):
        from redb.extractors.decompiler.apk.analyzer import _normalize_androguard_operands
        result = _normalize_androguard_operands(
            "sput-object",
            "v0, Lcom/Foo;->data [B"
        )
        assert result == "v0, Lcom/Foo;->data:[B"

    def test_non_invoke_non_field_passthrough(self):
        from redb.extractors.decompiler.apk.analyzer import _normalize_androguard_operands
        result = _normalize_androguard_operands(
            "const-string",
            'v0, "hello world"'
        )
        assert result == 'v0, "hello world"'

    def test_move_passthrough(self):
        from redb.extractors.decompiler.apk.analyzer import _normalize_androguard_operands
        result = _normalize_androguard_operands("move", "v0, v4")
        assert result == "v0, v4"

    def test_goto_passthrough(self):
        from redb.extractors.decompiler.apk.analyzer import _normalize_androguard_operands
        result = _normalize_androguard_operands("goto", "+005h")
        assert result == "+005h"


class TestSmaliCFG:
    """Tests for smali CFG construction and metrics computation."""

    def test_empty_body(self):
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        m = compute_cfg_metrics("")
        assert m.block_count == 0
        assert m.cyclomatic_complexity == 1

    def test_linear_method_apktool(self):
        """Single basic block — no branches."""
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        smali = textwrap.dedent("""\
            .registers 2
            invoke-direct {v1}, Ljava/lang/Object;-><init>()V
            const-string v0, "hello"
            iput-object v0, v1, LA;->a:Ljava/lang/String;
            return-void
        """)
        m = compute_cfg_metrics(smali)
        assert m.block_count == 1
        assert m.edge_count == 0
        assert m.cyclomatic_complexity == 1
        assert m.loop_count == 0
        assert m.max_depth == 0
        assert m.max_fan_out == 0

    def test_linear_method_androguard(self):
        """Single basic block — androguard format (no labels/directives)."""
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        smali = (
            "    invoke-direct {v1}, Ljava/lang/Object;-><init>()V\n"
            "    const-string v0, \"hello\"\n"
            "    iput-object v0, v1, LA;->a:Ljava/lang/String;\n"
            "    return-void"
        )
        m = compute_cfg_metrics(smali)
        assert m.block_count == 1
        assert m.edge_count == 0
        assert m.cyclomatic_complexity == 1

    def test_if_branch_apktool(self):
        """Diamond pattern: if-else with two paths merging."""
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        smali = textwrap.dedent("""\
            .registers 2
            const/4 v0, 0x0
            if-eqz v0, :cond_0
            const/4 v0, 0x1
            goto :goto_0
            :cond_0
            const/4 v0, 0x2
            :goto_0
            return v0
        """)
        m = compute_cfg_metrics(smali)
        # Blocks: [const,if] [const,goto] [const] [return]
        assert m.block_count == 4
        assert m.cyclomatic_complexity == 2  # E - N + 2
        assert m.loop_count == 0
        assert m.max_fan_out == 2  # if-branch has 2 successors

    def test_loop_apktool(self):
        """Simple loop: goto back to earlier label."""
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        smali = textwrap.dedent("""\
            .registers 2
            const/4 v0, 0x0
            :loop_start
            add-int/lit8 v0, v0, 0x1
            const/16 v1, 0xa
            if-lt v0, v1, :loop_start
            return v0
        """)
        m = compute_cfg_metrics(smali)
        assert m.loop_count == 1  # back edge from if-lt to loop_start
        assert m.cyclomatic_complexity >= 2

    def test_if_branch_androguard(self):
        """If-else in androguard offset format."""
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        smali = (
            "    const/4 v0, 0x0\n"
            "    if-eqz v0, +2h\n"        # skip 2 instructions ahead
            "    const/4 v0, 0x1\n"
            "    goto +1h\n"               # skip 1 ahead
            "    const/4 v0, 0x2\n"
            "    return v0"
        )
        m = compute_cfg_metrics(smali)
        assert m.block_count >= 3
        assert m.cyclomatic_complexity >= 2

    def test_multiple_if_branches(self):
        """Multiple if-branches increase cyclomatic complexity."""
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        smali = textwrap.dedent("""\
            .registers 3
            if-eqz v0, :cond_0
            if-eqz v1, :cond_1
            const/4 v2, 0x0
            goto :end
            :cond_0
            const/4 v2, 0x1
            goto :end
            :cond_1
            const/4 v2, 0x2
            :end
            return v2
        """)
        m = compute_cfg_metrics(smali)
        # Two if-branches: CC should be >= 3
        assert m.cyclomatic_complexity >= 3

    def test_return_terminates_block(self):
        """Return instruction terminates block with no successor."""
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        smali = textwrap.dedent("""\
            .registers 1
            const/4 v0, 0x0
            return v0
        """)
        m = compute_cfg_metrics(smali)
        assert m.block_count == 1
        assert m.edge_count == 0

    def test_throw_terminates_block(self):
        """Throw instruction terminates block with no successor."""
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        smali = textwrap.dedent("""\
            .registers 1
            new-instance v0, Ljava/lang/RuntimeException;
            invoke-direct {v0}, Ljava/lang/RuntimeException;-><init>()V
            throw v0
        """)
        m = compute_cfg_metrics(smali)
        assert m.block_count == 1
        assert m.edge_count == 0

    def test_max_depth_linear_chain(self):
        """Chain of blocks gives increasing depth."""
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        # 3 blocks chained: entry -> if -> fall-through -> return
        smali = textwrap.dedent("""\
            .registers 2
            const/4 v0, 0x0
            if-nez v0, :cond_0
            const/4 v0, 0x1
            :cond_0
            return v0
        """)
        m = compute_cfg_metrics(smali)
        assert m.max_depth >= 1

    def test_nested_loop_apktool(self):
        """Nested loop: two back edges."""
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        smali = textwrap.dedent("""\
            .registers 3
            const/4 v0, 0x0
            :outer
            const/4 v1, 0x0
            :inner
            add-int/lit8 v1, v1, 0x1
            if-lt v1, v2, :inner
            add-int/lit8 v0, v0, 0x1
            if-lt v0, v2, :outer
            return-void
        """)
        m = compute_cfg_metrics(smali)
        assert m.loop_count == 2

    def test_consistency_formula(self):
        """Verify E - N + 2 formula matches cyclomatic_complexity."""
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        smali = textwrap.dedent("""\
            .registers 2
            const/4 v0, 0x0
            if-eqz v0, :cond_0
            const/4 v0, 0x1
            goto :goto_0
            :cond_0
            const/4 v0, 0x2
            :goto_0
            return v0
        """)
        m = compute_cfg_metrics(smali)
        expected_cc = m.edge_count - m.block_count + 2
        assert m.cyclomatic_complexity == max(1, expected_cc)