From f66eb99465c61232a7f649e66bee59504bb0e52c Mon Sep 17 00:00:00 2001 From: Brianna Rainey Date: Wed, 28 Jan 2026 17:49:58 -0500 Subject: v2.2.1 - fix #74, fix #92, add optional 64th bar to Classic Visualizer, improve Conway default (#93) * update gitignore ignore profiling and coverage data * F1 opens help window, create appName variable, move undostack class * fix kaleidoscope effect, increase default Y values by +4 the increased y values allow the cells to continue animating for more than 60 minutes instead of 30 (at default 60f/t) * update version number * add minimumWidth to undo history window * Classic Visualizer: option to include 64th bar * Waveform component: fix #74 - new animation speed option * move shared visualizer code into toolkit * Waveform component: compress audio by default * Waveform component: fix 100% animation speed * new components receive random color * update to Qt 6 * fix pushbutton stylesheet * fix #92: replace ok/cancel with save/discard/cancel * remove obsolete PaintColor subclass * mv common shadow code into addShadow func * add 3rd option of ok/cancel back to showMessage the 3 options are: - ok - ok/cancel - save/discard/cancel * Image component: add shadow option * small test of rgbFromString * fix color tuple string * test another way to get comp names from CLI * rename component tests, add some more * Image component: scale shadow based on resolution * catch AttributeError if previewRender returns None * Text component: fix blur radius only able to increase the relativeWidgets system causes QDoubleSpinbox to only allow increases, because it really only works with integeres, so I changed the blur radius into a normal QSpinBox. I noted where the problem exists within component.py for future reference. This commit also removes an unneeded VerticalLayout from the ui file * remove unnecessary QVBoxLayout * paste shadow at x,y instead of using offset method * fix tests due to shadow change * don't print warning in connectWidget due to QFontComboBox--- tests/test_classic_visualizer.py | 71 ---------------------------------------- tests/test_commandline_parser.py | 7 +++- tests/test_comp_color.py | 22 +++++++++++++ tests/test_comp_image.py | 50 ++++++++++++++++++++++++++++ tests/test_comp_life.py | 23 +++++++++++++ tests/test_comp_original.py | 68 ++++++++++++++++++++++++++++++++++++++ tests/test_comp_spectrum.py | 20 +++++++++++ tests/test_comp_text.py | 45 +++++++++++++++++++++++++ tests/test_comp_waveform.py | 17 ++++++++++ tests/test_image_comp.py | 50 ---------------------------- tests/test_text_comp.py | 34 ------------------- tests/test_toolkit_common.py | 33 ++++++++++++++++++- 12 files changed, 283 insertions(+), 157 deletions(-) delete mode 100644 tests/test_classic_visualizer.py create mode 100644 tests/test_comp_color.py create mode 100644 tests/test_comp_image.py create mode 100644 tests/test_comp_life.py create mode 100644 tests/test_comp_original.py create mode 100644 tests/test_comp_spectrum.py create mode 100644 tests/test_comp_text.py create mode 100644 tests/test_comp_waveform.py delete mode 100644 tests/test_image_comp.py delete mode 100644 tests/test_text_comp.py (limited to 'tests') diff --git a/tests/test_classic_visualizer.py b/tests/test_classic_visualizer.py deleted file mode 100644 index e301263..0000000 --- a/tests/test_classic_visualizer.py +++ /dev/null @@ -1,71 +0,0 @@ -from avp.command import Command -from pytestqt import qtbot -from pytest import fixture -from . import audioData, MockSignal, imageDataSum - - -sampleSize = 1470 # 44100 / 30 = 1470 - - -@fixture -def coreWithClassicComp(qtbot): - """Fixture providing a Command object with Classic Visualizer component added""" - command = Command() - command.core.insertComponent( - 0, command.core.moduleIndexFor("Classic Visualizer"), command - ) - yield command.core - - -def test_comp_classic_added(coreWithClassicComp): - """Add Classic Visualizer to core""" - assert len(coreWithClassicComp.selectedComponents) == 1 - - -def test_comp_classic_removed(coreWithClassicComp): - """Remove Classic Visualizer from core""" - coreWithClassicComp.removeComponent(0) - assert len(coreWithClassicComp.selectedComponents) == 0 - - -def test_comp_classic_drawBars(coreWithClassicComp, audioData): - """Call drawBars after creating audio spectrum data manually.""" - - spectrumArray = { - 0: coreWithClassicComp.selectedComponents[0].transformData( - 0, audioData[0], sampleSize, 0.08, 0.8, None, 20 - ) - } - for i in range(sampleSize, len(audioData[0]), sampleSize): - spectrumArray[i] = coreWithClassicComp.selectedComponents[0].transformData( - i, - audioData[0], - sampleSize, - 0.08, - 0.8, - spectrumArray[i - sampleSize].copy(), - 20, - ) - image = coreWithClassicComp.selectedComponents[0].drawBars( - 1920, 1080, spectrumArray[sampleSize * 4], (0, 0, 0), 0 - ) - assert imageDataSum(image) == 37872316 - - -def test_comp_classic_drawBars_using_preFrameRender(coreWithClassicComp, audioData): - """Call drawBars after creating audio spectrum data using preFrameRender.""" - comp = coreWithClassicComp.selectedComponents[0] - comp.preFrameRender( - completeAudioArray=audioData[0], - sampleSize=sampleSize, - progressBarSetText=MockSignal(), - progressBarUpdate=MockSignal(), - ) - image = comp.drawBars( - 1920, - 1080, - coreWithClassicComp.selectedComponents[0].spectrumArray[sampleSize * 4], - (0, 0, 0), - 0, - ) - assert imageDataSum(image) == 37872316 diff --git a/tests/test_commandline_parser.py b/tests/test_commandline_parser.py index d092072..77836ce 100644 --- a/tests/test_commandline_parser.py +++ b/tests/test_commandline_parser.py @@ -51,6 +51,11 @@ def test_commandline_parses_classic_by_alias(qtbot): assert command.parseCompName("original") == "Classic Visualizer" -def test_commandline_parses_conway_by_name(qtbot): +def test_commandline_parses_conway_by_short_name(qtbot): command = Command() assert command.parseCompName("conway") == "Conway's Game of Life" + + +def test_commandline_parses_image_by_name(qtbot): + command = Command() + assert command.parseCompName("image") == "Image" diff --git a/tests/test_comp_color.py b/tests/test_comp_color.py new file mode 100644 index 0000000..6b82e4c --- /dev/null +++ b/tests/test_comp_color.py @@ -0,0 +1,22 @@ +from avp.command import Command +from pytestqt import qtbot +from pytest import fixture +from . import imageDataSum + + +@fixture +def coreWithColorComp(qtbot): + """Fixture providing a Command object with Color component added""" + command = Command() + command.settings.setValue("outputHeight", 1080) + command.settings.setValue("outputWidth", 1920) + command.core.insertComponent(0, command.core.moduleIndexFor("Color"), command) + yield command.core + + +def test_comp_color_set_color(coreWithColorComp): + "Set imagePath of Image component" + comp = coreWithColorComp.selectedComponents[0] + comp.page.lineEdit_color1.setText("111,111,111") + image = comp.previewRender() + assert imageDataSum(image) == 1219276800 diff --git a/tests/test_comp_image.py b/tests/test_comp_image.py new file mode 100644 index 0000000..a4f05e1 --- /dev/null +++ b/tests/test_comp_image.py @@ -0,0 +1,50 @@ +from avp.command import Command +from pytestqt import qtbot +from pytest import fixture +from . import audioData, MockSignal, imageDataSum, getTestDataPath + + +sampleSize = 1470 # 44100 / 30 = 1470 + + +@fixture +def coreWithImageComp(qtbot): + """Fixture providing a Command object with Image component added""" + command = Command() + command.settings.setValue("outputHeight", 1080) + command.settings.setValue("outputWidth", 1920) + command.core.insertComponent(0, command.core.moduleIndexFor("Image"), command) + yield command.core + + +def test_comp_image_set_path(coreWithImageComp): + "Set imagePath of Image component" + comp = coreWithImageComp.selectedComponents[0] + comp.imagePath = getTestDataPath("test.jpg") + image = comp.previewRender() + assert imageDataSum(image) == 463711601 + + +def test_comp_image_scale_50_1080p(coreWithImageComp): + """Image component stretches image to 50% at 1080p""" + comp = coreWithImageComp.selectedComponents[0] + comp.imagePath = getTestDataPath("test.jpg") + image = comp.previewRender() + sum = imageDataSum(image) + comp.page.spinBox_scale.setValue(50) + assert imageDataSum(comp.previewRender()) - sum / 4 < 2000 + + +def test_comp_image_scale_50_720p(coreWithImageComp): + """Image component stretches image to 50% at 720p""" + comp = coreWithImageComp.selectedComponents[0] + comp.imagePath = getTestDataPath("test.jpg") + comp.page.spinBox_scale.setValue(50) + image = comp.previewRender() + sum = imageDataSum(image) + comp.parent.settings.setValue("outputHeight", 720) + comp.parent.settings.setValue("outputWidth", 1280) + newImage = comp.previewRender() + assert image.width == 1920 + assert newImage.width == 1280 + assert imageDataSum(comp.previewRender()) == sum diff --git a/tests/test_comp_life.py b/tests/test_comp_life.py new file mode 100644 index 0000000..ad78e52 --- /dev/null +++ b/tests/test_comp_life.py @@ -0,0 +1,23 @@ +from avp.command import Command +from pytestqt import qtbot +from pytest import fixture +from . import imageDataSum + + +@fixture +def coreWithLifeComp(qtbot): + """Fixture providing a Command object with Waveform component added""" + command = Command() + command.settings.setValue("outputHeight", 1080) + command.settings.setValue("outputWidth", 1920) + command.core.insertComponent( + 0, command.core.moduleIndexFor("Conway's Game of Life"), command + ) + yield command.core + + +def test_comp_life_previewRender(coreWithLifeComp): + comp = coreWithLifeComp.selectedComponents[0] + comp.page.lineEdit_color.setText("111,111,111") + image = comp.previewRender() + assert imageDataSum(image) == 339785512 diff --git a/tests/test_comp_original.py b/tests/test_comp_original.py new file mode 100644 index 0000000..6264644 --- /dev/null +++ b/tests/test_comp_original.py @@ -0,0 +1,68 @@ +from avp.command import Command +from avp.toolkit.visualizer import transformData +from pytestqt import qtbot +from pytest import fixture +from . import audioData, MockSignal, imageDataSum + + +sampleSize = 1470 # 44100 / 30 = 1470 + + +@fixture +def coreWithClassicComp(qtbot): + """Fixture providing a Command object with Classic Visualizer component added""" + command = Command() + command.core.insertComponent( + 0, command.core.moduleIndexFor("Classic Visualizer"), command + ) + yield command.core + + +def test_comp_classic_added(coreWithClassicComp): + """Add Classic Visualizer to core""" + assert len(coreWithClassicComp.selectedComponents) == 1 + + +def test_comp_classic_removed(coreWithClassicComp): + """Remove Classic Visualizer from core""" + coreWithClassicComp.removeComponent(0) + assert len(coreWithClassicComp.selectedComponents) == 0 + + +def test_comp_classic_drawBars(coreWithClassicComp, audioData): + """Call drawBars after creating audio spectrum data manually.""" + + spectrumArray = {0: transformData(0, audioData[0], sampleSize, 0.08, 0.8, None, 20)} + for i in range(sampleSize, len(audioData[0]), sampleSize): + spectrumArray[i] = transformData( + i, + audioData[0], + sampleSize, + 0.08, + 0.8, + spectrumArray[i - sampleSize].copy(), + 20, + ) + image = coreWithClassicComp.selectedComponents[0].drawBars( + 1920, 1080, spectrumArray[sampleSize * 4], (0, 0, 0), 0 + ) + assert imageDataSum(image) == 37872316 + + +def test_comp_classic_drawBars_using_preFrameRender(coreWithClassicComp, audioData): + """Call drawBars after creating audio spectrum data using preFrameRender.""" + comp = coreWithClassicComp.selectedComponents[0] + comp.preFrameRender( + completeAudioArray=audioData[0], + sampleSize=sampleSize, + progressBarSetText=MockSignal(), + progressBarUpdate=MockSignal(), + ) + image = comp.drawBars( + 1920, + 1080, + coreWithClassicComp.selectedComponents[0].spectrumArray[sampleSize * 4], + (0, 0, 0), + 0, + ) + assert imageDataSum(image) == 37872316 diff --git a/tests/test_comp_spectrum.py b/tests/test_comp_spectrum.py new file mode 100644 index 0000000..44fb257 --- /dev/null +++ b/tests/test_comp_spectrum.py @@ -0,0 +1,20 @@ +from avp.command import Command +from pytestqt import qtbot +from pytest import fixture +from . import imageDataSum + + +@fixture +def coreWithSpectrumComp(qtbot): + """Fixture providing a Command object with Spectrum component added""" + command = Command() + command.settings.setValue("outputHeight", 1080) + command.settings.setValue("outputWidth", 1920) + command.core.insertComponent(0, command.core.moduleIndexFor("Spectrum"), command) + yield command.core + + +def test_comp_waveform_previewRender(coreWithSpectrumComp): + comp = coreWithSpectrumComp.selectedComponents[0] + image = comp.previewRender() + assert imageDataSum(image) == 71992628 diff --git a/tests/test_comp_text.py b/tests/test_comp_text.py new file mode 100644 index 0000000..e389ff9 --- /dev/null +++ b/tests/test_comp_text.py @@ -0,0 +1,45 @@ +from avp.command import Command +from PyQt6.QtGui import QFont +from pytestqt import qtbot +from pytest import fixture, mark +from . import audioData, MockSignal, imageDataSum + + +@fixture +def coreWithTextComp(qtbot): + """Fixture providing a Command object with Title Text component added""" + command = Command() + command.core.insertComponent(0, command.core.moduleIndexFor("Title Text"), command) + yield command.core + + +def setTextSettings(comp): + comp.page.spinBox_fontSize.setValue(40) + comp.page.checkBox_shadow.setChecked(True) + comp.page.spinBox_shadBlur.setValue(0) + comp.page.spinBox_shadX.setValue(2) + comp.page.spinBox_shadY.setValue(-2) + comp.page.fontComboBox_titleFont.setCurrentFont(QFont("Noto Sans")) + comp.page.lineEdit_textColor.setText("255,255,255") + + +@mark.parametrize( + "width, height", + ((1920, 1080), (1280, 720)), +) +def test_comp_text_renderFrame(coreWithTextComp, width, height): + """Call renderFrame of Title Text component added to Command object.""" + comp = coreWithTextComp.selectedComponents[0] + comp.parent.settings.setValue("outputWidth", width) + comp.parent.settings.setValue("outputHeight", height) + setTextSettings(comp) + comp.centerXY() + image = comp.frameRender(0) + assert comp.titleFont.family() == "Noto Sans" + assert comp.xPosition == width / 2 + assert image.width == width + assert comp.fontSize == 40 + assert comp.shadX == 2 + assert comp.shadY == -2 + assert comp.shadBlur == 0 + assert imageDataSum(image) == 727403 or 738586 diff --git a/tests/test_comp_waveform.py b/tests/test_comp_waveform.py new file mode 100644 index 0000000..a71040b --- /dev/null +++ b/tests/test_comp_waveform.py @@ -0,0 +1,17 @@ +from avp.command import Command +from pytestqt import qtbot +from pytest import fixture + + +@fixture +def coreWithWaveformComp(qtbot): + """Fixture providing a Command object with Waveform component added""" + command = Command() + command.core.insertComponent(0, command.core.moduleIndexFor("Waveform"), command) + yield command.core + + +def test_comp_waveform_setColor(coreWithWaveformComp): + comp = coreWithWaveformComp.selectedComponents[0] + comp.page.lineEdit_color.setText("255,255,255") + assert comp.color == (255, 255, 255) diff --git a/tests/test_image_comp.py b/tests/test_image_comp.py deleted file mode 100644 index a4f05e1..0000000 --- a/tests/test_image_comp.py +++ /dev/null @@ -1,50 +0,0 @@ -from avp.command import Command -from pytestqt import qtbot -from pytest import fixture -from . import audioData, MockSignal, imageDataSum, getTestDataPath - - -sampleSize = 1470 # 44100 / 30 = 1470 - - -@fixture -def coreWithImageComp(qtbot): - """Fixture providing a Command object with Image component added""" - command = Command() - command.settings.setValue("outputHeight", 1080) - command.settings.setValue("outputWidth", 1920) - command.core.insertComponent(0, command.core.moduleIndexFor("Image"), command) - yield command.core - - -def test_comp_image_set_path(coreWithImageComp): - "Set imagePath of Image component" - comp = coreWithImageComp.selectedComponents[0] - comp.imagePath = getTestDataPath("test.jpg") - image = comp.previewRender() - assert imageDataSum(image) == 463711601 - - -def test_comp_image_scale_50_1080p(coreWithImageComp): - """Image component stretches image to 50% at 1080p""" - comp = coreWithImageComp.selectedComponents[0] - comp.imagePath = getTestDataPath("test.jpg") - image = comp.previewRender() - sum = imageDataSum(image) - comp.page.spinBox_scale.setValue(50) - assert imageDataSum(comp.previewRender()) - sum / 4 < 2000 - - -def test_comp_image_scale_50_720p(coreWithImageComp): - """Image component stretches image to 50% at 720p""" - comp = coreWithImageComp.selectedComponents[0] - comp.imagePath = getTestDataPath("test.jpg") - comp.page.spinBox_scale.setValue(50) - image = comp.previewRender() - sum = imageDataSum(image) - comp.parent.settings.setValue("outputHeight", 720) - comp.parent.settings.setValue("outputWidth", 1280) - newImage = comp.previewRender() - assert image.width == 1920 - assert newImage.width == 1280 - assert imageDataSum(comp.previewRender()) == sum diff --git a/tests/test_text_comp.py b/tests/test_text_comp.py deleted file mode 100644 index 23dd1fd..0000000 --- a/tests/test_text_comp.py +++ /dev/null @@ -1,34 +0,0 @@ -from avp.command import Command -from PyQt6.QtGui import QFont -from pytestqt import qtbot -from pytest import fixture -from . import audioData, MockSignal, imageDataSum - - -@fixture -def coreWithTextComp(qtbot): - """Fixture providing a Command object with Title Text component added""" - command = Command() - command.core.insertComponent(0, command.core.moduleIndexFor("Title Text"), command) - yield command.core - - -def test_comp_text_renderFrame_resize(coreWithTextComp): - """Call renderFrame of Title Text component added to Command object.""" - comp = coreWithTextComp.selectedComponents[0] - comp.parent.settings.setValue("outputWidth", 1920) - comp.parent.settings.setValue("outputHeight", 1080) - comp.parent.core.updateComponent(0) - comp.titleFont = QFont("Noto Sans") - image = comp.frameRender(0) - assert imageDataSum(image) == 2957069 - - -def test_comp_text_renderFrame(coreWithTextComp): - """Call renderFrame of Title Text component added to Command object.""" - comp = coreWithTextComp.selectedComponents[0] - comp.parent.settings.setValue("outputWidth", 1280) - comp.parent.settings.setValue("outputHeight", 720) - comp.parent.core.updateComponent(0) - image = comp.frameRender(0) - assert imageDataSum(image) == 1412293 or 1379298 diff --git a/tests/test_toolkit_common.py b/tests/test_toolkit_common.py index d903842..8e9dca2 100644 --- a/tests/test_toolkit_common.py +++ b/tests/test_toolkit_common.py @@ -1,6 +1,27 @@ +from pytest import fixture from pytestqt import qtbot from avp.command import Command -from avp.toolkit import blockSignals +from avp.toolkit import blockSignals, rgbFromString + + +@fixture +def gotWarning(): + """Check if a function called log.warning""" + import avp.toolkit.common as tk + warning = False + def gotWarning(): + nonlocal warning + return warning + class log: + def warning(self, *args): + nonlocal warning + warning = True + oldLog = tk.log + tk.log = log() + try: + yield gotWarning + finally: + tk.log = oldLog def test_blockSignals(qtbot): @@ -11,3 +32,13 @@ def test_blockSignals(qtbot): with blockSignals(comp.page.spinBox_scale): assert comp.page.spinBox_scale.signalsBlocked() == True assert comp.page.spinBox_scale.signalsBlocked() == False + + +def test_rgbFromString(gotWarning): + assert rgbFromString("255,255,255") == (255, 255, 255) + assert not gotWarning() + + +def test_rgbFromString_error(gotWarning): + assert rgbFromString("255,255,256") == (255, 255, 255) + assert gotWarning() \ No newline at end of file -- cgit v1.2.3