mirror of
https://github.com/fergalmoran/picard.git
synced 2026-01-06 16:44:06 +00:00
Refactored cover art file tests into format specific test files
This commit is contained in:
@@ -12,6 +12,7 @@ import picard.formats
|
||||
from picard.formats import ext_to_format
|
||||
from picard.metadata import Metadata
|
||||
|
||||
|
||||
settings = {
|
||||
'clear_existing_tags': False,
|
||||
'embed_only_one_front_image': False,
|
||||
@@ -141,12 +142,10 @@ def skipUnlessTestfile(func):
|
||||
# prevent unittest to run tests in those classes
|
||||
class CommonTests:
|
||||
|
||||
class SimpleFormatsTest(PicardTestCase):
|
||||
|
||||
class BaseFileTest(PicardTestCase):
|
||||
testfile = None
|
||||
testfile_ext = None
|
||||
testfile_path = None
|
||||
expected_info = None
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
@@ -167,6 +166,10 @@ class CommonTests:
|
||||
shutil.copy(filename, copy)
|
||||
return copy
|
||||
|
||||
class SimpleFormatsTest(BaseFileTest):
|
||||
|
||||
expected_info = None
|
||||
|
||||
@skipUnlessTestfile
|
||||
def test_can_open_and_save(self):
|
||||
metadata = Metadata()
|
||||
|
||||
143
test/formats/coverart.py
Normal file
143
test/formats/coverart.py
Normal file
@@ -0,0 +1,143 @@
|
||||
import os.path
|
||||
|
||||
from PyQt5 import QtCore
|
||||
|
||||
from picard import config
|
||||
from picard.coverart.image import (
|
||||
CoverArtImage,
|
||||
TagCoverArtImage,
|
||||
)
|
||||
import picard.formats
|
||||
from picard.metadata import Metadata
|
||||
from .common import (
|
||||
CommonTests,
|
||||
skipUnlessTestfile,
|
||||
)
|
||||
|
||||
|
||||
def file_save_image(filename, image):
|
||||
f = picard.formats.open_(filename)
|
||||
metadata = Metadata()
|
||||
metadata.images.append(image)
|
||||
f._save(filename, metadata)
|
||||
|
||||
|
||||
def load_coverart_file(filename):
|
||||
with open(os.path.join('test', 'data', filename), 'rb') as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
# prevent unittest to run tests in those classes
|
||||
class CommonCoverArtTests:
|
||||
|
||||
class CoverArtTest(CommonTests.BaseFileTest):
|
||||
|
||||
supports_types = True
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.jpegdata = load_coverart_file('mb.jpg')
|
||||
self.pngdata = load_coverart_file('mb.png')
|
||||
self.addCleanup(QtCore.QObject.tagger.run_cleanup)
|
||||
|
||||
@skipUnlessTestfile
|
||||
def test_cover_art(self):
|
||||
source_types = ["front", "booklet"]
|
||||
# Use reasonable large data > 64kb.
|
||||
# This checks a mutagen error with ASF files.
|
||||
tests = [
|
||||
CoverArtImage(data=self.jpegdata + b"a" * 1024 * 128, types=source_types),
|
||||
CoverArtImage(data=self.pngdata + b"a" * 1024 * 128, types=source_types),
|
||||
]
|
||||
for test in tests:
|
||||
file_save_image(self.filename, test)
|
||||
f = picard.formats.open_(self.filename)
|
||||
loaded_metadata = f._load(self.filename)
|
||||
image = loaded_metadata.images[0]
|
||||
self.assertEqual(test.mimetype, image.mimetype)
|
||||
self.assertEqual(test, image)
|
||||
|
||||
def test_cover_art_with_types(self):
|
||||
expected = set('abcdefg'[:]) if self.supports_types else set('a')
|
||||
f = picard.formats.open_(self.filename)
|
||||
f._save(self.filename, self._cover_metadata())
|
||||
|
||||
f = picard.formats.open_(self.filename)
|
||||
loaded_metadata = f._load(self.filename)
|
||||
found = set([chr(img.data[-1]) for img in loaded_metadata.images])
|
||||
self.assertEqual(expected, found)
|
||||
|
||||
@skipUnlessTestfile
|
||||
def test_cover_art_types_only_one_front(self):
|
||||
config.setting['embed_only_one_front_image'] = True
|
||||
f = picard.formats.open_(self.filename)
|
||||
f._save(self.filename, self._cover_metadata())
|
||||
|
||||
f = picard.formats.open_(self.filename)
|
||||
loaded_metadata = f._load(self.filename)
|
||||
self.assertEqual(1, len(loaded_metadata.images))
|
||||
self.assertEqual(ord('a'), loaded_metadata.images[0].data[-1])
|
||||
|
||||
def _cover_metadata(self):
|
||||
imgdata = self.jpegdata
|
||||
metadata = Metadata()
|
||||
metadata.images.append(
|
||||
TagCoverArtImage(
|
||||
file='a',
|
||||
tag='a',
|
||||
data=imgdata + b'a',
|
||||
support_types=True,
|
||||
types=[u'booklet', u'front'],
|
||||
)
|
||||
)
|
||||
metadata.images.append(
|
||||
TagCoverArtImage(
|
||||
file='b',
|
||||
tag='b',
|
||||
data=imgdata + b'b',
|
||||
support_types=True,
|
||||
types=[u'back'],
|
||||
)
|
||||
)
|
||||
metadata.images.append(
|
||||
TagCoverArtImage(
|
||||
file='c',
|
||||
tag='c',
|
||||
data=imgdata + b'c',
|
||||
support_types=True,
|
||||
types=[u'front'],
|
||||
)
|
||||
)
|
||||
metadata.images.append(
|
||||
TagCoverArtImage(
|
||||
file='d',
|
||||
tag='d',
|
||||
data=imgdata + b'd',
|
||||
)
|
||||
)
|
||||
metadata.images.append(
|
||||
TagCoverArtImage(
|
||||
file='e',
|
||||
tag='e',
|
||||
data=imgdata + b'e',
|
||||
is_front=False
|
||||
)
|
||||
)
|
||||
metadata.images.append(
|
||||
TagCoverArtImage(
|
||||
file='f',
|
||||
tag='f',
|
||||
data=imgdata + b'f',
|
||||
types=[u'front']
|
||||
)
|
||||
)
|
||||
metadata.images.append(
|
||||
TagCoverArtImage(
|
||||
file='g',
|
||||
tag='g',
|
||||
data=imgdata + b'g',
|
||||
types=[u'back'],
|
||||
is_front=True
|
||||
)
|
||||
)
|
||||
return metadata
|
||||
@@ -2,6 +2,7 @@ from .common import (
|
||||
CommonTests,
|
||||
load_metadata,
|
||||
)
|
||||
from .coverart import CommonCoverArtTests
|
||||
|
||||
|
||||
class MonkeysAudioTest(CommonTests.TagFormatsTest):
|
||||
@@ -76,3 +77,8 @@ class OptimFROGDUalStreamTest(CommonTests.TagFormatsTest):
|
||||
def test_format(self):
|
||||
metadata = load_metadata(self.filename)
|
||||
self.assertEqual(metadata['~format'], 'OptimFROG DualStream Audio')
|
||||
|
||||
|
||||
class ApeCoverArtTest(CommonCoverArtTests.CoverArtTest):
|
||||
testfile = 'test.ape'
|
||||
supports_types = False
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from .common import CommonTests
|
||||
from .coverart import CommonCoverArtTests
|
||||
|
||||
|
||||
class ASFTest(CommonTests.TagFormatsTest):
|
||||
@@ -21,3 +22,11 @@ class WMATest(CommonTests.TagFormatsTest):
|
||||
'~sample_rate': '44100',
|
||||
'~bitrate': '64.0',
|
||||
}
|
||||
|
||||
|
||||
class AsfCoverArtTest(CommonCoverArtTests.CoverArtTest):
|
||||
testfile = 'test.asf'
|
||||
|
||||
|
||||
class WmaCoverArtTest(CommonCoverArtTests.CoverArtTest):
|
||||
testfile = 'test.wma'
|
||||
|
||||
@@ -1,315 +0,0 @@
|
||||
import os.path
|
||||
import shutil
|
||||
from tempfile import mkstemp
|
||||
from test.picardtestcase import PicardTestCase
|
||||
|
||||
from PyQt5 import QtCore
|
||||
|
||||
from picard import (
|
||||
config,
|
||||
# log,
|
||||
)
|
||||
from picard.coverart.image import (
|
||||
CoverArtImage,
|
||||
TagCoverArtImage,
|
||||
)
|
||||
import picard.formats
|
||||
from picard.metadata import Metadata
|
||||
from .common import (
|
||||
load_raw,
|
||||
settings,
|
||||
)
|
||||
|
||||
|
||||
class TestCoverArt(PicardTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
with open(os.path.join('test', 'data', 'mb.jpg'), 'rb') as f:
|
||||
self.jpegdata = f.read()
|
||||
with open(os.path.join('test', 'data', 'mb.png'), 'rb') as f:
|
||||
self.pngdata = f.read()
|
||||
|
||||
def _common_set_up(self, extra=None):
|
||||
config.setting = settings.copy()
|
||||
if extra is not None:
|
||||
config.setting.update(extra)
|
||||
|
||||
def _set_up(self, original, extra=None):
|
||||
fd, self.filename = mkstemp(suffix=os.path.splitext(original)[1])
|
||||
os.close(fd)
|
||||
shutil.copy(original, self.filename)
|
||||
self._common_set_up(extra)
|
||||
|
||||
def _common_tear_down(self):
|
||||
QtCore.QObject.tagger.run_cleanup()
|
||||
|
||||
def _tear_down(self):
|
||||
os.unlink(self.filename)
|
||||
self._common_tear_down()
|
||||
|
||||
def test_coverartimage(self):
|
||||
tests = {
|
||||
'jpg': {
|
||||
'mime': 'image/jpeg',
|
||||
'data': self.jpegdata
|
||||
},
|
||||
'png': {
|
||||
'mime': 'image/png',
|
||||
'data': self.pngdata
|
||||
},
|
||||
}
|
||||
tmp_files = []
|
||||
for t in tests:
|
||||
imgdata = tests[t]['data']
|
||||
imgdata2 = imgdata + b'xxx'
|
||||
# set data once
|
||||
coverartimage = CoverArtImage(
|
||||
data=imgdata2
|
||||
)
|
||||
tmp_file = coverartimage.tempfile_filename
|
||||
tmp_files.append(tmp_file)
|
||||
filesize = os.path.getsize(tmp_file)
|
||||
# ensure file was written, and check its length
|
||||
self.assertEqual(filesize, len(imgdata2))
|
||||
self.assertEqual(coverartimage.data, imgdata2)
|
||||
|
||||
# set data again, with another payload
|
||||
coverartimage.set_data(imgdata)
|
||||
|
||||
tmp_file = coverartimage.tempfile_filename
|
||||
tmp_files.append(tmp_file)
|
||||
filesize = os.path.getsize(tmp_file)
|
||||
# check file length again
|
||||
self.assertEqual(filesize, len(imgdata))
|
||||
self.assertEqual(coverartimage.data, imgdata)
|
||||
|
||||
QtCore.QObject.tagger.run_cleanup()
|
||||
|
||||
def test_asf(self):
|
||||
self._test_cover_art(os.path.join('test', 'data', 'test.wma'))
|
||||
|
||||
def test_ape(self):
|
||||
self._test_cover_art(os.path.join('test', 'data', 'test.wv'))
|
||||
|
||||
def test_mp3(self):
|
||||
self._test_cover_art(os.path.join('test', 'data', 'test.mp3'))
|
||||
|
||||
def test_mp4(self):
|
||||
self._test_cover_art(os.path.join('test', 'data', 'test.m4a'))
|
||||
|
||||
def test_ogg(self):
|
||||
self._test_cover_art(os.path.join('test', 'data', 'test.ogg'))
|
||||
|
||||
def test_flac(self):
|
||||
self._test_cover_art(os.path.join('test', 'data', 'test.flac'))
|
||||
|
||||
# test for multiple images added to files, some types don't accept more than
|
||||
# one, and there is no guarantee that order is preserved
|
||||
def test_asf_types(self):
|
||||
self._test_cover_art_types(os.path.join('test', 'data', 'test.wma'),
|
||||
set('abcdefg'[:]))
|
||||
|
||||
def test_ape_types(self):
|
||||
self._test_cover_art_types(os.path.join('test', 'data', 'test.wv'),
|
||||
set('a'))
|
||||
|
||||
def test_mp3_types(self):
|
||||
self._test_cover_art_types(os.path.join('test', 'data', 'test.mp3'),
|
||||
set('abcdefg'[:]))
|
||||
|
||||
def test_mp4_types(self):
|
||||
self._test_cover_art_types(os.path.join('test', 'data', 'test.m4a'),
|
||||
set('abcdefg'[:]))
|
||||
|
||||
def test_ogg_types(self):
|
||||
self._test_cover_art_types(os.path.join('test', 'data', 'test.ogg'),
|
||||
set('abcdefg'[:]))
|
||||
|
||||
def test_flac_types(self):
|
||||
self._test_cover_art_types(os.path.join('test', 'data', 'test.flac'),
|
||||
set('abcdefg'[:]))
|
||||
|
||||
def test_asf_types_only_front(self):
|
||||
self._test_cover_art_types_only_front(
|
||||
os.path.join('test', 'data', 'test.wma'),
|
||||
set('a'))
|
||||
|
||||
def test_ape_types_only_front(self):
|
||||
self._test_cover_art_types_only_front(
|
||||
os.path.join('test', 'data', 'test.wv'),
|
||||
set('a'))
|
||||
|
||||
def test_mp3_types_only_front(self):
|
||||
self._test_cover_art_types_only_front(
|
||||
os.path.join('test', 'data', 'test.mp3'),
|
||||
set('a'))
|
||||
|
||||
def test_mp4_types_only_front(self):
|
||||
self._test_cover_art_types_only_front(
|
||||
os.path.join('test', 'data', 'test.m4a'),
|
||||
set('a'))
|
||||
|
||||
def test_ogg_types_only_front(self):
|
||||
self._test_cover_art_types_only_front(
|
||||
os.path.join('test', 'data', 'test.ogg'),
|
||||
set('a'))
|
||||
|
||||
def test_flac_types_only_front(self):
|
||||
self._test_cover_art_types_only_front(
|
||||
os.path.join('test', 'data', 'test.flac'),
|
||||
set('a'))
|
||||
|
||||
def test_flac_set_picture_dimensions(self):
|
||||
self._set_up(os.path.join('test', 'data', 'test.flac'))
|
||||
try:
|
||||
tests = [
|
||||
CoverArtImage(data=self.jpegdata),
|
||||
CoverArtImage(data=self.pngdata),
|
||||
]
|
||||
for test in tests:
|
||||
self._file_save_image(self.filename, test)
|
||||
raw_metadata = load_raw(self.filename)
|
||||
pic = raw_metadata.pictures[0]
|
||||
self.assertNotEqual(pic.width, 0)
|
||||
self.assertEqual(pic.width, test.width)
|
||||
self.assertNotEqual(pic.height, 0)
|
||||
self.assertEqual(pic.height, test.height)
|
||||
finally:
|
||||
self._tear_down()
|
||||
|
||||
def _test_cover_art(self, filename):
|
||||
self._set_up(filename)
|
||||
try:
|
||||
source_types = ["front", "booklet"]
|
||||
# Use reasonable large data > 64kb.
|
||||
# This checks a mutagen error with ASF files.
|
||||
tests = [
|
||||
CoverArtImage(data=self.jpegdata + b"a" * 1024 * 128, types=source_types),
|
||||
CoverArtImage(data=self.pngdata + b"a" * 1024 * 128, types=source_types),
|
||||
]
|
||||
for test in tests:
|
||||
self._file_save_image(self.filename, test)
|
||||
f = picard.formats.open_(self.filename)
|
||||
loaded_metadata = f._load(self.filename)
|
||||
image = loaded_metadata.images[0]
|
||||
self.assertEqual(test.mimetype, image.mimetype)
|
||||
self.assertEqual(test, image)
|
||||
finally:
|
||||
self._tear_down()
|
||||
|
||||
@staticmethod
|
||||
def _file_save_image(filename, image):
|
||||
f = picard.formats.open_(filename)
|
||||
metadata = Metadata()
|
||||
metadata.images.append(image)
|
||||
f._save(filename, metadata)
|
||||
|
||||
def _cover_metadata(self):
|
||||
imgdata = self.jpegdata
|
||||
metadata = Metadata()
|
||||
metadata.images.append(
|
||||
TagCoverArtImage(
|
||||
file='a',
|
||||
tag='a',
|
||||
data=imgdata + b'a',
|
||||
support_types=True,
|
||||
types=[u'booklet', u'front'],
|
||||
)
|
||||
)
|
||||
metadata.images.append(
|
||||
TagCoverArtImage(
|
||||
file='b',
|
||||
tag='b',
|
||||
data=imgdata + b'b',
|
||||
support_types=True,
|
||||
types=[u'back'],
|
||||
)
|
||||
)
|
||||
metadata.images.append(
|
||||
TagCoverArtImage(
|
||||
file='c',
|
||||
tag='c',
|
||||
data=imgdata + b'c',
|
||||
support_types=True,
|
||||
types=[u'front'],
|
||||
)
|
||||
)
|
||||
metadata.images.append(
|
||||
TagCoverArtImage(
|
||||
file='d',
|
||||
tag='d',
|
||||
data=imgdata + b'd',
|
||||
)
|
||||
)
|
||||
metadata.images.append(
|
||||
TagCoverArtImage(
|
||||
file='e',
|
||||
tag='e',
|
||||
data=imgdata + b'e',
|
||||
is_front=False
|
||||
)
|
||||
)
|
||||
metadata.images.append(
|
||||
TagCoverArtImage(
|
||||
file='f',
|
||||
tag='f',
|
||||
data=imgdata + b'f',
|
||||
types=[u'front']
|
||||
)
|
||||
)
|
||||
metadata.images.append(
|
||||
TagCoverArtImage(
|
||||
file='g',
|
||||
tag='g',
|
||||
data=imgdata + b'g',
|
||||
types=[u'back'],
|
||||
is_front=True
|
||||
)
|
||||
)
|
||||
return metadata
|
||||
|
||||
def test_is_front_image(self):
|
||||
self._common_set_up()
|
||||
try:
|
||||
m = self._cover_metadata()
|
||||
front_images = set('acdfg'[:])
|
||||
found = set()
|
||||
for img in m.images:
|
||||
if img.is_front_image():
|
||||
found.add(img.tag)
|
||||
self.assertEqual(front_images, found)
|
||||
finally:
|
||||
self._common_tear_down()
|
||||
|
||||
def _test_cover_art_types(self, filename, expect):
|
||||
self._set_up(filename)
|
||||
expect = {ord(char) for char in expect}
|
||||
try:
|
||||
f = picard.formats.open_(self.filename)
|
||||
f._save(self.filename, self._cover_metadata())
|
||||
|
||||
f = picard.formats.open_(self.filename)
|
||||
loaded_metadata = f._load(self.filename)
|
||||
found = set()
|
||||
for n, image in enumerate(loaded_metadata.images):
|
||||
found.add(image.data[-1])
|
||||
self.assertEqual(expect, found)
|
||||
finally:
|
||||
self._tear_down()
|
||||
|
||||
def _test_cover_art_types_only_front(self, filename, expect):
|
||||
self._set_up(filename, {'embed_only_one_front_image': True})
|
||||
expect = {ord(char) for char in expect}
|
||||
try:
|
||||
f = picard.formats.open_(self.filename)
|
||||
f._save(self.filename, self._cover_metadata())
|
||||
|
||||
f = picard.formats.open_(self.filename)
|
||||
loaded_metadata = f._load(self.filename)
|
||||
found = set()
|
||||
for n, image in enumerate(loaded_metadata.images):
|
||||
found.add(image.data[-1])
|
||||
self.assertEqual(expect, found)
|
||||
finally:
|
||||
self._tear_down()
|
||||
@@ -12,6 +12,7 @@ from .common import (
|
||||
save_metadata,
|
||||
skipUnlessTestfile,
|
||||
)
|
||||
from .coverart import CommonCoverArtTests
|
||||
|
||||
|
||||
# prevent unittest to run tests in those classes
|
||||
@@ -229,3 +230,7 @@ class AIFFTest(CommonId3Tests.Id3Test):
|
||||
'~sample_rate': '44100',
|
||||
'~bitrate': '1411.2',
|
||||
}
|
||||
|
||||
|
||||
class Mp3CoverArtTest(CommonCoverArtTests.CoverArtTest):
|
||||
testfile = 'test.mp3'
|
||||
|
||||
@@ -3,6 +3,7 @@ from .common import (
|
||||
CommonTests,
|
||||
load_metadata,
|
||||
)
|
||||
from .coverart import CommonCoverArtTests
|
||||
|
||||
|
||||
class MP4Test(CommonTests.TagFormatsTest):
|
||||
@@ -29,3 +30,7 @@ class MP4Test(CommonTests.TagFormatsTest):
|
||||
def test_format(self):
|
||||
metadata = load_metadata(self.filename)
|
||||
self.assertIn('AAC LC', metadata['~format'])
|
||||
|
||||
|
||||
class Mp4CoverArtTest(CommonCoverArtTests.CoverArtTest):
|
||||
testfile = 'test.m4a'
|
||||
|
||||
@@ -6,13 +6,19 @@ from picard import (
|
||||
config,
|
||||
log,
|
||||
)
|
||||
from picard.coverart.image import CoverArtImage
|
||||
from picard.formats import vorbis
|
||||
from .common import (
|
||||
CommonTests,
|
||||
load_metadata,
|
||||
load_raw,
|
||||
save_and_load_metadata,
|
||||
skipUnlessTestfile,
|
||||
)
|
||||
from .coverart import (
|
||||
CommonCoverArtTests,
|
||||
file_save_image,
|
||||
)
|
||||
|
||||
|
||||
# prevent unittest to run tests in those classes
|
||||
@@ -81,7 +87,7 @@ class VorbisUtilTest(PicardTestCase):
|
||||
self.assertEqual(sanitized, ' }')
|
||||
|
||||
|
||||
class FlacCoverArtTest(CommonCoverArtTests.CoverArtTestCase):
|
||||
class FlacCoverArtTest(CommonCoverArtTests.CoverArtTest):
|
||||
testfile = 'test.flac'
|
||||
|
||||
def test_set_picture_dimensions(self):
|
||||
@@ -99,5 +105,5 @@ class FlacCoverArtTest(CommonCoverArtTests.CoverArtTestCase):
|
||||
self.assertEqual(pic.height, test.height)
|
||||
|
||||
|
||||
class OggCoverArtTest(CommonCoverArtTests.CoverArtTestCase):
|
||||
class OggCoverArtTest(CommonCoverArtTests.CoverArtTest):
|
||||
testfile = 'test.ogg'
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
import os.path
|
||||
import unittest
|
||||
|
||||
from PyQt5 import QtCore
|
||||
|
||||
from test.picardtestcase import (
|
||||
PicardTestCase,
|
||||
create_fake_png,
|
||||
@@ -84,6 +87,27 @@ class CoverArtImageTest(PicardTestCase):
|
||||
self.assertEqual(image2, image3)
|
||||
self.assertNotEqual(image2, image4)
|
||||
|
||||
def test_set_data(self):
|
||||
self.addCleanup(QtCore.QObject.tagger.run_cleanup)
|
||||
imgdata = data=create_fake_png(b'a')
|
||||
imgdata2 = data=create_fake_png(b'xxx')
|
||||
# set data once
|
||||
coverartimage = CoverArtImage(data=imgdata2)
|
||||
tmp_file = coverartimage.tempfile_filename
|
||||
filesize = os.path.getsize(tmp_file)
|
||||
# ensure file was written, and check its length
|
||||
self.assertEqual(filesize, len(imgdata2))
|
||||
self.assertEqual(coverartimage.data, imgdata2)
|
||||
|
||||
# set data again, with another payload
|
||||
coverartimage.set_data(imgdata)
|
||||
|
||||
tmp_file = coverartimage.tempfile_filename
|
||||
filesize = os.path.getsize(tmp_file)
|
||||
# check file length again
|
||||
self.assertEqual(filesize, len(imgdata))
|
||||
self.assertEqual(coverartimage.data, imgdata)
|
||||
|
||||
|
||||
class LocalFileCoverArtImageTest(PicardTestCase):
|
||||
def test_set_file_url(self):
|
||||
|
||||
Reference in New Issue
Block a user