# upscale-qt - tests for the non-GUI helpers and a GUI smoke test # Copyright (C) 2026 Danilo M. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import os import tempfile from importlib.machinery import SourceFileLoader from importlib.util import module_from_spec, spec_from_loader TMP = tempfile.mkdtemp(prefix='upscale-qt-test-') os.environ['QT_QPA_PLATFORM'] = 'offscreen' os.environ['XDG_CONFIG_HOME'] = os.path.join(TMP, 'config') HERE = os.path.dirname(os.path.abspath(__file__)) _loader = SourceFileLoader('upscale_qt', os.path.join(HERE, 'upscale-qt')) uq = module_from_spec(spec_from_loader('upscale_qt', _loader)) _loader.exec_module(uq) from PyQt6.QtGui import QColor, QImage, QImageReader # noqa: E402 def test_list_models(): d = os.path.join(TMP, 'models') os.makedirs(d) for f in ('b.safetensors', 'a.pth', 'notes.txt', 'c.GGUF'): open(os.path.join(d, f), 'w').close() assert uq.list_models(d) == ['a.pth', 'b.safetensors', 'c.GGUF'] assert uq.list_models(os.path.join(TMP, 'missing')) == [] def test_descriptions(): d = os.path.join(TMP, 'models') with open(os.path.join(d, 'models.txt'), 'w') as f: f.write('# comment = ignored\n' 'a.pth = Clean photos: people, nature\n' '\n' 'no separator here\n' ' c.GGUF=Anime \n') desc = uq.read_descriptions(d) assert desc == {'a.pth': 'Clean photos: people, nature', 'c.GGUF': 'Anime'} assert uq.model_label('a.pth', desc) == 'Clean photos: people, nature [a]' assert uq.model_label('b.safetensors', desc) == 'b.safetensors' assert uq.read_descriptions(os.path.join(TMP, 'missing')) == {} def test_args(): a = uq.sd_args('/m/x.pth', '/in.png', '/out.png') assert a == ['-M', 'upscale', '--upscale-model', '/m/x.pth', '-i', '/in.png', '-o', '/out.png'] def test_save_over(): path = os.path.join(TMP, 'photo.JPG') # uppercase suffix on purpose small = QImage(4, 4, QImage.Format.Format_RGB32) small.fill(QColor('red')) assert small.save(path, 'jpeg') big = QImage(16, 16, QImage.Format.Format_RGB32) big.fill(QColor('blue')) assert uq.save_over(big, path) assert QImage(path).width() == 16 assert bytes(QImageReader.imageFormat(path)) == b'jpeg' assert not os.path.exists(path + '.part') from PyQt6.QtWidgets import QApplication # noqa: E402 APP = QApplication.instance() or QApplication([]) def test_compare_view(): before = QImage(10, 10, QImage.Format.Format_RGB32) before.fill(QColor('red')) after = QImage(40, 40, QImage.Format.Format_RGB32) after.fill(QColor('blue')) v = uq.CompareView() v.resize(400, 400) # at or above the minimum size v.set_images(before, after) shot = v.grab().toImage() # left of the divider shows before, right shows after assert shot.pixelColor(100, 200) == QColor('red') assert shot.pixelColor(300, 200) == QColor('blue') def test_main_window(): w = uq.Main() w.cfg.setValue('upscalers_dir', os.path.join(TMP, 'models')) w.reload_models() assert not w.a_up.isEnabled() # no image yet path = os.path.join(TMP, 'in.png') img = QImage(8, 6, QImage.Format.Format_RGB32) img.fill(QColor('green')) img.save(path) w.load(path) assert len(w.jobs) == 1 and w.jobs[0].image.size() == img.size() assert os.path.exists(w.jobs[0].input) assert w.a_up.isEnabled() and not w.a_save.isEnabled() assert w.models.itemText(0) == 'Clean photos: people, nature [a]' assert w.models.currentData() == 'a.pth' if __name__ == '__main__': for name, fn in list(globals().items()): if name.startswith('test_'): fn() print('ok', name)