diff --git a/.gitignore b/.gitignore
index 9800ef6..278948f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,9 @@ prof/
.venv/
.env/
.vscode/
+tests/data/log/
+tests/data/settings.ini
+tests/data/autosave.avp
*.mkv
*.mp4
*.wav
diff --git a/pyproject.toml b/pyproject.toml
index 2f0647c..ea27839 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,7 +6,7 @@ build-backend = "uv_build"
name = "audio-visualizer-python"
description = "Create audio visualization videos from a GUI or commandline"
readme = "README.md"
-version = "2.2.1"
+version = "2.2.2"
requires-python = ">= 3.12"
license = "MIT"
classifiers=[
diff --git a/src/avp/__init__.py b/src/avp/__init__.py
index a88bf10..9de9f93 100644
--- a/src/avp/__init__.py
+++ b/src/avp/__init__.py
@@ -3,7 +3,7 @@
import logging
-__version__ = "2.2.1"
+__version__ = "2.2.2"
class Logger(logging.getLoggerClass()):
diff --git a/src/avp/cli.py b/src/avp/cli.py
index 02ceee6..0176f76 100644
--- a/src/avp/cli.py
+++ b/src/avp/cli.py
@@ -5,6 +5,11 @@
import string
+from .core import Core
+
+# Core class must store settings as class variables
+# before we can use many things in AVP
+Core.storeSettings()
log = logging.getLogger("AVP.Main")
diff --git a/src/avp/command.py b/src/avp/command.py
index 7a77848..870391b 100644
--- a/src/avp/command.py
+++ b/src/avp/command.py
@@ -256,7 +256,6 @@ def parseCompName(self, name):
for i, compFileName in enumerate(compFileNames):
if name.lower() in compFileName:
return self.core.compNames[i]
- return
return None
diff --git a/src/avp/components/spectrum.ui b/src/avp/components/spectrum.ui
index c6a8a15..3bde075 100644
--- a/src/avp/components/spectrum.ui
+++ b/src/avp/components/spectrum.ui
@@ -27,909 +27,899 @@
-
-
-
- 4
-
+
-
-
+
+
+
+ 0
+ 0
+
+
+
+ Type
+
+
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Type
-
-
-
+
-
-
-
-
-
- Spectrum
-
-
- -
-
- Histogram
-
-
- -
-
- Vector Scope
-
-
- -
-
- Musical Scale
-
-
- -
-
- Phase
-
-
-
+
+ Spectrum
+
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 5
- 20
-
-
-
+
+ Histogram
+
-
-
-
-
- 0
- 0
-
-
-
- X
-
-
+
+ Vector Scope
+
-
-
-
-
- 0
- 0
-
-
-
-
- 80
- 16777215
-
-
-
- -10000
-
-
- 10000
-
-
+
+ Musical Scale
+
-
-
-
-
- 0
- 0
-
-
-
- Y
-
-
+
+ Phase
+
- -
-
-
-
- 0
- 0
-
-
-
-
- 80
- 16777215
-
-
-
-
- 0
- 0
-
-
-
- -10000
-
-
- 10000
-
-
- 0
-
-
-
-
+
-
-
-
-
-
-
- Compress
-
-
-
- -
-
-
- Mono
-
-
-
- -
-
-
- Mirror
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Hue
-
-
- 4
-
-
-
- -
-
-
- °
-
-
- 359
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Scale
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- QAbstractSpinBox::UpDownArrows
-
-
- %
-
-
- 10
-
-
- 400
-
-
- 100
-
-
-
-
+
+
+ Qt::Orientation::Horizontal
+
+
+ QSizePolicy::Policy::Fixed
+
+
+
+ 5
+ 20
+
+
+
-
-
+
-
+
0
0
-
- false
+
+ X
-
- QFrame::NoFrame
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 80
+ 16777215
+
+
+
+ -10000
+
+
+ 10000
+
+
+
+ -
+
+
+
+ 0
+ 0
+
-
- QFrame::Plain
+
+ Y
-
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 80
+ 16777215
+
+
+
+
+ 0
+ 0
+
+
+
+ -10000
+
+
+ 10000
+
+
0
-
-
-
-
- 0
- 0
- 561
- 66
-
-
-
+
+
+
+
+ -
+
+
-
+
+
+ Compress
+
+
+
+ -
+
+
+ Mono
+
+
+
+ -
+
+
+ Mirror
+
+
+
+ -
+
+
+ Qt::Orientation::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Hue
+
+
+ 4
+
+
+
+ -
+
+
+ °
+
+
+ 359
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Scale
+
+
+ Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter
+
+
+
+ -
+
+
+ QAbstractSpinBox::ButtonSymbols::UpDownArrows
+
+
+ %
+
+
+ 10
+
+
+ 400
+
+
+ 100
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ false
+
+
+ QFrame::Shape::NoFrame
+
+
+ QFrame::Shadow::Plain
+
+
+ 0
+
+
+
+
+
+ 0
+ 0
+ 561
+ 76
+
+
+
+
+ QLayout::SizeConstraint::SetMaximumSize
+
+
+ 0
+
+
-
+
- QLayout::SetMaximumSize
-
-
- 0
+ QLayout::SizeConstraint::SetDefaultConstraint
-
-
-
- QLayout::SetDefaultConstraint
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 31
- 0
-
-
-
- Window
-
-
- 4
-
-
-
- -
-
-
-
-
- hann
-
-
- -
-
- gauss
-
-
- -
-
- tukey
-
-
- -
-
- dolph
-
-
- -
-
- cauchy
-
-
- -
-
- parzen
-
-
- -
-
- poisson
-
-
- -
-
- rect
-
-
- -
-
- bartlett
-
-
- -
-
- hanning
-
-
- -
-
- hamming
-
-
- -
-
- blackman
-
-
- -
-
- welch
-
-
- -
-
- flattop
-
-
- -
-
- bharris
-
-
- -
-
- bnuttall
-
-
- -
-
- lanczos
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Amplitude
-
-
- 4
-
-
-
- -
-
-
-
-
- Square root
-
-
- -
-
- Cubic root
-
-
- -
-
- 4thrt
-
-
- -
-
- 5thrt
-
-
- -
-
- Linear
-
-
- -
-
- Logarithmic
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::MinimumExpanding
-
-
-
- 10
- 20
-
-
-
-
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 31
+ 0
+
+
+
+ Window
+
+
+ 4
+
+
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Color
-
-
- 4
-
-
-
- -
-
-
-
-
- Channel
-
-
- -
-
- Intensity
-
-
- -
-
- Rainbow
-
-
- -
-
- Moreland
-
-
- -
-
- Nebulae
-
-
- -
-
- Fire
-
-
- -
-
- Fiery
-
-
- -
-
- Fruit
-
-
- -
-
- Cool
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::MinimumExpanding
-
-
-
- 10
- 20
-
-
-
-
-
+
+ -
+
+ hann
+
+
+ -
+
+ gauss
+
+
+ -
+
+ tukey
+
+
+ -
+
+ dolph
+
+
+ -
+
+ cauchy
+
+
+ -
+
+ parzen
+
+
+ -
+
+ poisson
+
+
+ -
+
+ rect
+
+
+ -
+
+ bartlett
+
+
+ -
+
+ hanning
+
+
+ -
+
+ hamming
+
+
+ -
+
+ blackman
+
+
+ -
+
+ welch
+
+
+ -
+
+ flattop
+
+
+ -
+
+ bharris
+
+
+ -
+
+ bnuttall
+
+
+ -
+
+ lanczos
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Amplitude
+
+
+ 4
+
+
+
+ -
+
+
-
+
+ Square root
+
+
+ -
+
+ Cubic root
+
+
+ -
+
+ 4thrt
+
+
+ -
+
+ 5thrt
+
+
+ -
+
+ Linear
+
+
+ -
+
+ Logarithmic
+
+
+
+
+ -
+
+
+ Qt::Orientation::Horizontal
+
+
+ QSizePolicy::Policy::MinimumExpanding
+
+
+
+ 10
+ 20
+
+
+
-
-
-
-
-
-
- -1
- -1
- 561
- 31
-
-
-
+
+ -
+
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Display Scale
-
-
- 4
-
-
-
- -
-
-
-
-
- Logarithmic
-
-
- -
-
- Square root
-
-
- -
-
- Cubic root
-
-
- -
-
- Linear
-
-
- -
-
- Reverse Log
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Amplitude
-
-
- 4
-
-
-
- -
-
-
-
-
- Logarithmic
-
-
- -
-
- Linear
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Minimum
-
-
-
- 40
- 20
-
-
-
-
-
+
+
+
+ 0
+ 0
+
+
+
+ Color
+
+
+ 4
+
+
+
+ -
+
+
-
+
+ Channel
+
+
+ -
+
+ Intensity
+
+
+ -
+
+ Rainbow
+
+
+ -
+
+ Moreland
+
+
+ -
+
+ Nebulae
+
+
+ -
+
+ Fire
+
+
+ -
+
+ Fiery
+
+
+ -
+
+ Fruit
+
+
+ -
+
+ Cool
+
+
+
+
+ -
+
+
+ Qt::Orientation::Horizontal
+
+
+ QSizePolicy::Policy::MinimumExpanding
+
+
+
+ 10
+ 20
+
+
+
-
-
-
-
-
-
- -1
- -1
- 585
- 64
-
-
-
+
+
+
+
+
+
+
+
+ -1
+ -1
+ 561
+ 36
+
+
+
+ -
+
-
-
-
-
-
-
- Mode
-
-
-
- -
-
-
-
-
- lissajous
-
-
- -
-
- lissajous_xy
-
-
- -
-
- polar
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Amplitude
-
-
- 4
-
-
-
- -
-
-
-
-
- Linear
-
-
- -
-
- Square root
-
-
- -
-
- Cubic root
-
-
- -
-
- Logarithmic
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
+
+
+
+ 0
+ 0
+
+
+
+ Display Scale
+
+
+ 4
+
+
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Zoom
-
-
- 4
-
-
-
- -
-
-
- 1
-
-
- 10
-
-
-
- -
-
-
- Line
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
+
+ -
+
+ Logarithmic
+
+
+ -
+
+ Square root
+
+
+ -
+
+ Cubic root
+
+
+ -
+
+ Linear
+
+
+ -
+
+ Reverse Log
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Amplitude
+
+
+ 4
+
+
+
+ -
+
+
-
+
+ Logarithmic
+
+
+ -
+
+ Linear
+
+
+
+
+ -
+
+
+ Qt::Orientation::Horizontal
+
+
+ QSizePolicy::Policy::Minimum
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -1
+ -1
+ 585
+ 76
+
+
+
+ -
+
+
-
+
+
+ Mode
+
+
+
+ -
+
+
-
+
+ lissajous
+
+
+ -
+
+ lissajous_xy
+
+
+ -
+
+ polar
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Amplitude
+
+
+ 4
+
+
+
+ -
+
+
-
+
+ Linear
+
+
+ -
+
+ Square root
+
+
+ -
+
+ Cubic root
+
+
+ -
+
+ Logarithmic
+
+
+
+
+ -
+
+
+ Qt::Orientation::Horizontal
+
+
+
+ 40
+ 20
+
+
+
-
-
-
-
-
-
- 0
- 0
- 561
- 31
-
-
-
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Zoom
+
+
+ 4
+
+
+
+ -
+
+
+ 1
+
+
+ 10
+
+
+
+ -
+
+
+ Line
+
+
+
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Timeclamp
-
-
- 4
-
-
-
- -
-
-
- s
-
-
- 3
-
-
- 0.002000000000000
-
-
- 1.000000000000000
-
-
- 0.010000000000000
-
-
- 0.017000000000000
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
+
+
+ Qt::Orientation::Horizontal
+
+
+
+ 40
+ 20
+
+
+
-
-
-
-
-
-
- 0
- 0
- 551
- 31
-
-
-
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 561
+ 36
+
+
+
+ -
+
-
-
+
+
+
+ 0
+ 0
+
+
+
+ Timeclamp
+
+
+ 4
+
+
+
+ -
+
+
+ s
+
+
+ 3
+
+
+ 0.002000000000000
+
+
+ 1.000000000000000
+
+
+ 0.010000000000000
+
+
+ 0.017000000000000
+
+
+
+ -
+
+
+ Qt::Orientation::Horizontal
+
+
+
+ 40
+ 20
+
+
+
-
-
+
+
-
-
+
+
+
+
+
+ 0
+ 0
+ 551
+ 31
+
+
+
+ -
+
+
+
+
+
+
-
- Qt::Vertical
+ Qt::Orientation::Vertical
- QSizePolicy::Fixed
+ QSizePolicy::Policy::Fixed
diff --git a/src/avp/core.py b/src/avp/core.py
index 099b0b4..1e9a9c3 100644
--- a/src/avp/core.py
+++ b/src/avp/core.py
@@ -420,14 +420,18 @@ def reset(self):
Core.canceled = False
@classmethod
- def storeSettings(cls):
+ def storeSettings(cls, dataDir=None):
"""Store settings/paths to directories as class variables"""
from .__init__ import wd
from .toolkit.ffmpeg import findFfmpeg
cls.wd = wd
- dataDir = QtCore.QStandardPaths.writableLocation(
- QtCore.QStandardPaths.StandardLocation.AppConfigLocation
+ dataDir = (
+ QtCore.QStandardPaths.writableLocation(
+ QtCore.QStandardPaths.StandardLocation.AppConfigLocation
+ )
+ if dataDir is None
+ else dataDir
)
# Windows: C:/Users//AppData/Local/audio-visualizer
# macOS: ~/Library/Preferences/audio-visualizer
@@ -589,7 +593,3 @@ def makeLogger(deleteOldLogs=False, fileLogLvl=None):
libLog.addHandler(libLogFile)
# lowest level must be explicitly set on the root Logger
libLog.setLevel(0)
-
-
-# always store settings in class variables even if a Core object is not created
-Core.storeSettings()
diff --git a/src/avp/gui/mainwindow.py b/src/avp/gui/mainwindow.py
index 5a051fd..3221783 100644
--- a/src/avp/gui/mainwindow.py
+++ b/src/avp/gui/mainwindow.py
@@ -414,8 +414,10 @@ def changedField():
# Add initial components if none are in the list
if not self.core.selectedComponents:
- self.core.insertComponent(0, 0, self)
- self.core.insertComponent(1, 1, self)
+ self.core.insertComponent(
+ 0, self.core.moduleIndexFor("Classic Visualizer"), self
+ )
+ self.core.insertComponent(1, self.core.moduleIndexFor("Color"), self)
# set colors to white and black to match classic appearance of program
self.core.selectedComponents[0].page.lineEdit_visColor.setText(
"255,255,255"
@@ -900,8 +902,8 @@ def clear(self):
def createNewProject(self, prompt=True):
if prompt:
ch = self.openSaveChangesDialog("starting a new project")
- if ch is None:
- return
+ if ch is None:
+ return
self.clear()
self.currentProject = None
diff --git a/tests/__init__.py b/tests/__init__.py
index b615681..df08c7c 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1,8 +1,9 @@
import os
import numpy
-# core always has to be imported first
-import avp.core
+from avp.core import Core
+from avp.command import Command
+from avp.gui.mainwindow import MainWindow
from avp.toolkit.ffmpeg import readAudioFile
from pytest import fixture
@@ -10,16 +11,47 @@
@fixture
def audioData():
"""Fixture that gives a tuple of (completeAudioArray, duration)"""
- soundFile = getTestDataPath("test.ogg")
+ # Core.storeSettings() needed to store ffmpeg bin location
+ initCore()
+ soundFile = getTestDataPath("inputfiles/test.ogg")
yield readAudioFile(soundFile, MockVideoWorker())
-def getTestDataPath(filename):
+@fixture
+def command(qtbot):
+ initCore()
+ command = Command()
+ command.quit = lambda _: None
+ yield command
+
+
+@fixture
+def window(qtbot):
+ initCore()
+ window = MainWindow(None, None)
+ window.clear()
+ qtbot.addWidget(window)
+ window.settings.setValue("outputWidth", 1920)
+ window.settings.setValue("outputHeight", 1080)
+ yield window
+
+
+def getTestDataPath(filename=""):
"""Get path to a file in the ./data directory"""
tests_dir = os.path.dirname(os.path.abspath(__file__))
return os.path.join(tests_dir, "data", filename)
+def initCore():
+ testDataDir = getTestDataPath()
+ unwanted = ["autosave.avp", "settings.ini"]
+ for file in unwanted:
+ filename = os.path.join(testDataDir, "autosave.avp")
+ if os.path.exists(filename):
+ os.remove(filename)
+ Core.storeSettings(testDataDir)
+
+
class MockSignal:
"""Pretends to be a pyqtSignal"""
diff --git a/tests/data/test.jpg b/tests/data/inputfiles/test.jpg
similarity index 100%
rename from tests/data/test.jpg
rename to tests/data/inputfiles/test.jpg
diff --git a/tests/data/test.ogg b/tests/data/inputfiles/test.ogg
similarity index 100%
rename from tests/data/test.ogg
rename to tests/data/inputfiles/test.ogg
diff --git a/tests/data/test.png b/tests/data/inputfiles/test.png
similarity index 100%
rename from tests/data/test.png
rename to tests/data/inputfiles/test.png
diff --git a/tests/data/projects/testproject.avp b/tests/data/projects/testproject.avp
new file mode 100644
index 0000000..fd6b6eb
--- /dev/null
+++ b/tests/data/projects/testproject.avp
@@ -0,0 +1,17 @@
+[Components]
+Classic Visualizer
+1
+OrderedDict({'bars': 63, 'layout': 0, 'preset': None, 'scale': 20, 'smooth': 0, 'visColor': (255, 255, 255), 'y': 0.0})
+Color
+1
+OrderedDict({'LG_end': 0.0, 'LG_start': 0.0, 'RG_centre': 0.0015625, 'RG_end': 0.0, 'RG_start': 0.0, 'color1': (0, 0, 0), 'color2': (133, 133, 133), 'fillType': 0, 'height': 1.0, 'preset': None, 'spread': 0, 'stretch': False, 'trans': False, 'width': 1.0, 'x': 0.0, 'y': 0.0})
+
+[Settings]
+componentDir=tests/data/inputfiles
+inputDir=tests/data/inputfiles
+presetDir=tests/data/presets
+projectDir=tests/data/projects
+
+[WindowFields]
+lineEdit_audioFile=tests/data/test.ogg
+lineEdit_outputFile=
diff --git a/tests/test_commandline_export.py b/tests/test_commandline_export.py
index 05ead77..6d7f068 100644
--- a/tests/test_commandline_export.py
+++ b/tests/test_commandline_export.py
@@ -1,14 +1,13 @@
import sys
import os
import tempfile
-from avp.command import Command
-from . import getTestDataPath
+from . import command, getTestDataPath, MockSignal
from pytestqt import qtbot
-def test_commandline_classic_export(qtbot):
+def test_commandline_classic_export(qtbot, command):
"""Run Qt event loop and create a video in the system /tmp or /temp"""
- soundFile = getTestDataPath("test.ogg")
+ soundFile = getTestDataPath("inputfiles/test.ogg")
outputDir = tempfile.mkdtemp(prefix="avp-test-")
outputFilename = os.path.join(outputDir, "output.mp4")
sys.argv = [
@@ -21,9 +20,6 @@ def test_commandline_classic_export(qtbot):
"-o",
outputFilename,
]
-
- command = Command()
- command.quit = lambda _: None
command.parseArgs()
# Command object now has a video_thread Worker which is exporting the video
diff --git a/tests/test_commandline_parser.py b/tests/test_commandline_parser.py
index 77836ce..186c602 100644
--- a/tests/test_commandline_parser.py
+++ b/tests/test_commandline_parser.py
@@ -1,39 +1,34 @@
import sys
import pytest
-from avp.command import Command
from pytestqt import qtbot
+from . import command
-def test_commandline_help(qtbot):
- command = Command()
+def test_commandline_help(qtbot, command):
sys.argv = ["", "--help"]
with pytest.raises(SystemExit):
command.parseArgs()
-def test_commandline_help_if_bad_args(qtbot):
- command = Command()
+def test_commandline_help_if_bad_args(qtbot, command):
sys.argv = ["", "--junk"]
with pytest.raises(SystemExit):
command.parseArgs()
-def test_commandline_launches_gui_if_verbose(qtbot):
- command = Command()
+def test_commandline_launches_gui_if_verbose(qtbot, command):
sys.argv = ["", "--verbose"]
mode = command.parseArgs()
assert mode == "GUI"
-def test_commandline_launches_gui_if_verbose_with_project(qtbot):
- command = Command()
+def test_commandline_launches_gui_if_verbose_with_project(qtbot, command):
sys.argv = ["", "test", "--verbose"]
mode = command.parseArgs()
assert mode == "GUI"
-def test_commandline_tries_to_export(qtbot):
- command = Command()
+def test_commandline_tries_to_export(qtbot, command):
didCallFunction = False
def captureFunction(*args):
@@ -46,16 +41,13 @@ def captureFunction(*args):
assert didCallFunction
-def test_commandline_parses_classic_by_alias(qtbot):
- command = Command()
+def test_commandline_parses_classic_by_alias(qtbot, command):
assert command.parseCompName("original") == "Classic Visualizer"
-def test_commandline_parses_conway_by_short_name(qtbot):
- command = Command()
+def test_commandline_parses_conway_by_short_name(qtbot, command):
assert command.parseCompName("conway") == "Conway's Game of Life"
-def test_commandline_parses_image_by_name(qtbot):
- command = Command()
+def test_commandline_parses_image_by_name(qtbot, command):
assert command.parseCompName("image") == "Image"
diff --git a/tests/test_comp_color.py b/tests/test_comp_color.py
index 6b82e4c..48b07ff 100644
--- a/tests/test_comp_color.py
+++ b/tests/test_comp_color.py
@@ -1,13 +1,12 @@
from avp.command import Command
from pytestqt import qtbot
from pytest import fixture
-from . import imageDataSum
+from . import imageDataSum, command
@fixture
-def coreWithColorComp(qtbot):
+def coreWithColorComp(qtbot, command):
"""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)
diff --git a/tests/test_comp_image.py b/tests/test_comp_image.py
index a4f05e1..c580d5a 100644
--- a/tests/test_comp_image.py
+++ b/tests/test_comp_image.py
@@ -1,16 +1,15 @@
from avp.command import Command
from pytestqt import qtbot
from pytest import fixture
-from . import audioData, MockSignal, imageDataSum, getTestDataPath
+from . import audioData, command, MockSignal, imageDataSum, getTestDataPath
sampleSize = 1470 # 44100 / 30 = 1470
@fixture
-def coreWithImageComp(qtbot):
+def coreWithImageComp(qtbot, command):
"""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)
@@ -20,7 +19,7 @@ def coreWithImageComp(qtbot):
def test_comp_image_set_path(coreWithImageComp):
"Set imagePath of Image component"
comp = coreWithImageComp.selectedComponents[0]
- comp.imagePath = getTestDataPath("test.jpg")
+ comp.imagePath = getTestDataPath("inputfiles/test.jpg")
image = comp.previewRender()
assert imageDataSum(image) == 463711601
@@ -28,7 +27,7 @@ def test_comp_image_set_path(coreWithImageComp):
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")
+ comp.imagePath = getTestDataPath("inputfiles/test.jpg")
image = comp.previewRender()
sum = imageDataSum(image)
comp.page.spinBox_scale.setValue(50)
@@ -38,7 +37,7 @@ def test_comp_image_scale_50_1080p(coreWithImageComp):
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.imagePath = getTestDataPath("inputfiles/test.jpg")
comp.page.spinBox_scale.setValue(50)
image = comp.previewRender()
sum = imageDataSum(image)
diff --git a/tests/test_comp_life.py b/tests/test_comp_life.py
index ad78e52..3c02117 100644
--- a/tests/test_comp_life.py
+++ b/tests/test_comp_life.py
@@ -1,13 +1,12 @@
from avp.command import Command
from pytestqt import qtbot
from pytest import fixture
-from . import imageDataSum
+from . import imageDataSum, command
@fixture
-def coreWithLifeComp(qtbot):
+def coreWithLifeComp(qtbot, command):
"""Fixture providing a Command object with Waveform component added"""
- command = Command()
command.settings.setValue("outputHeight", 1080)
command.settings.setValue("outputWidth", 1920)
command.core.insertComponent(
diff --git a/tests/test_comp_original.py b/tests/test_comp_original.py
index 6264644..8cd00a4 100644
--- a/tests/test_comp_original.py
+++ b/tests/test_comp_original.py
@@ -2,16 +2,15 @@
from avp.toolkit.visualizer import transformData
from pytestqt import qtbot
from pytest import fixture
-from . import audioData, MockSignal, imageDataSum
+from . import audioData, command, MockSignal, imageDataSum
sampleSize = 1470 # 44100 / 30 = 1470
@fixture
-def coreWithClassicComp(qtbot):
+def coreWithClassicComp(qtbot, command):
"""Fixture providing a Command object with Classic Visualizer component added"""
- command = Command()
command.core.insertComponent(
0, command.core.moduleIndexFor("Classic Visualizer"), command
)
diff --git a/tests/test_comp_spectrum.py b/tests/test_comp_spectrum.py
index 44fb257..870185c 100644
--- a/tests/test_comp_spectrum.py
+++ b/tests/test_comp_spectrum.py
@@ -1,13 +1,12 @@
from avp.command import Command
from pytestqt import qtbot
from pytest import fixture
-from . import imageDataSum
+from . import imageDataSum, command
@fixture
-def coreWithSpectrumComp(qtbot):
+def coreWithSpectrumComp(qtbot, command):
"""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)
diff --git a/tests/test_comp_text.py b/tests/test_comp_text.py
index e389ff9..20b202d 100644
--- a/tests/test_comp_text.py
+++ b/tests/test_comp_text.py
@@ -2,13 +2,12 @@
from PyQt6.QtGui import QFont
from pytestqt import qtbot
from pytest import fixture, mark
-from . import audioData, MockSignal, imageDataSum
+from . import audioData, command, MockSignal, imageDataSum
@fixture
-def coreWithTextComp(qtbot):
+def coreWithTextComp(qtbot, command):
"""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
diff --git a/tests/test_comp_waveform.py b/tests/test_comp_waveform.py
index a71040b..eb5800d 100644
--- a/tests/test_comp_waveform.py
+++ b/tests/test_comp_waveform.py
@@ -1,12 +1,11 @@
-from avp.command import Command
from pytestqt import qtbot
from pytest import fixture
+from . import command
@fixture
-def coreWithWaveformComp(qtbot):
+def coreWithWaveformComp(qtbot, command):
"""Fixture providing a Command object with Waveform component added"""
- command = Command()
command.core.insertComponent(0, command.core.moduleIndexFor("Waveform"), command)
yield command.core
diff --git a/tests/test_mainwindow_projects.py b/tests/test_mainwindow_projects.py
new file mode 100644
index 0000000..8ad491a
--- /dev/null
+++ b/tests/test_mainwindow_projects.py
@@ -0,0 +1,40 @@
+from pytest import fixture
+from pytestqt import qtbot
+from . import getTestDataPath, window
+
+
+def test_mainwindow_clear(qtbot, window):
+ """MainWindow.clear() gives us a clean slate"""
+ assert len(window.core.selectedComponents) == 0
+
+
+def test_mainwindow_openProject(qtbot, window):
+ """Open testproject.avp using MainWindow.openProject()"""
+ window.openProject(getTestDataPath("projects/testproject.avp"), prompt=False)
+ assert len(window.core.selectedComponents) == 2
+
+
+def test_mainwindow_newProject_without_unsaved_changes(qtbot, window):
+ """Starting new project without unsaved changes"""
+ didCallFunction = False
+
+ def captureFunction(*args, **kwargs):
+ nonlocal didCallFunction
+ didCallFunction = True
+
+ window.createNewProject(prompt=False)
+ assert not didCallFunction
+ assert len(window.core.selectedComponents) == 0
+
+
+def test_mainwindow_newProject_with_unsaved_changes(qtbot, window):
+ """Starting new project with unsaved changes"""
+ didCallFunction = False
+
+ def captureFunction(*args, **kwargs):
+ nonlocal didCallFunction
+ didCallFunction = True
+
+ window.openSaveChangesDialog = captureFunction
+ window.createNewProject(prompt=True)
+ assert didCallFunction
diff --git a/tests/test_mainwindow_undostack.py b/tests/test_mainwindow_undostack.py
index 1eec1ef..ceaf87e 100644
--- a/tests/test_mainwindow_undostack.py
+++ b/tests/test_mainwindow_undostack.py
@@ -1,16 +1,7 @@
from pytest import fixture
from pytestqt import qtbot
from avp.gui.mainwindow import MainWindow
-from . import getTestDataPath
-
-
-@fixture
-def window(qtbot):
- window = MainWindow(None, None)
- qtbot.addWidget(window)
- window.settings.setValue("outputWidth", 1920)
- window.settings.setValue("outputHeight", 1080)
- yield window
+from . import getTestDataPath, window
def test_undo_classic_visualizer_sensitivity(window, qtbot):
@@ -20,7 +11,7 @@ def test_undo_classic_visualizer_sensitivity(window, qtbot):
0, window.core.moduleIndexFor("Classic Visualizer"), window
)
comp = window.core.selectedComponents[0]
- comp.imagePath = getTestDataPath("test.jpg")
+ comp.imagePath = getTestDataPath("inputfiles/test.jpg")
for i in range(1, 100):
comp.page.spinBox_scale.setValue(i)
assert comp.scale == 99
@@ -32,7 +23,7 @@ def test_undo_image_scale(window, qtbot):
"""Undo Image component scale setting should undo multiple merged actions."""
window.core.insertComponent(0, window.core.moduleIndexFor("Image"), window)
comp = window.core.selectedComponents[0]
- comp.imagePath = getTestDataPath("test.jpg")
+ comp.imagePath = getTestDataPath("inputfiles/test.jpg")
comp.page.spinBox_scale.setValue(100)
for i in range(10, 401):
comp.page.spinBox_scale.setValue(i)
diff --git a/tests/test_toolkit_common.py b/tests/test_toolkit_common.py
index 8e9dca2..b20ae53 100644
--- a/tests/test_toolkit_common.py
+++ b/tests/test_toolkit_common.py
@@ -2,20 +2,25 @@
from pytestqt import qtbot
from avp.command import Command
from avp.toolkit import blockSignals, rgbFromString
+from . import command
@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:
@@ -24,8 +29,7 @@ def warning(self, *args):
tk.log = oldLog
-def test_blockSignals(qtbot):
- command = Command()
+def test_blockSignals(qtbot, command):
command.core.insertComponent(0, 0, command)
comp = command.core.selectedComponents[0]
assert comp.page.spinBox_scale.signalsBlocked() == False
@@ -41,4 +45,4 @@ def test_rgbFromString(gotWarning):
def test_rgbFromString_error(gotWarning):
assert rgbFromString("255,255,256") == (255, 255, 255)
- assert gotWarning()
\ No newline at end of file
+ assert gotWarning()
diff --git a/tests/test_toolkit_ffmpeg.py b/tests/test_toolkit_ffmpeg.py
index b015470..363eba1 100644
--- a/tests/test_toolkit_ffmpeg.py
+++ b/tests/test_toolkit_ffmpeg.py
@@ -1,7 +1,8 @@
import pytest
+from avp.core import Core
from avp.command import Command
from avp.toolkit.ffmpeg import createFfmpegCommand
-from . import audioData
+from . import audioData, getTestDataPath, initCore
def test_readAudioFile_data(audioData):
@@ -14,6 +15,7 @@ def test_readAudioFile_duration(audioData):
@pytest.mark.parametrize("width, height", ((1920, 1080), (1280, 720)))
def test_createFfmpegCommand(width, height):
+ initCore()
command = Command()
command.settings.setValue("outputWidth", width)
command.settings.setValue("outputHeight", height)
diff --git a/uv.lock b/uv.lock
index edc9406..a23039a 100644
--- a/uv.lock
+++ b/uv.lock
@@ -4,7 +4,7 @@ requires-python = ">=3.12"
[[package]]
name = "audio-visualizer-python"
-version = "2.2.1"
+version = "2.2.2"
source = { editable = "." }
dependencies = [
{ name = "numpy" },