# -*- test-case-name: mv3d.test.test_asset -*- # Copyright (C) 2007-2009 Mortal Coil Games # See LICENSE for details. """ """ import os from zope.interface.verify import verifyClass from twisted.trial.unittest import TestCase from twisted.web.server import Site from twisted.web.resource import Resource from twisted.internet import reactor from twisted.internet.defer import inlineCallbacks, returnValue, FirstError from mv3d.test.mixins import withDataStore from mv3d.resource.iasset import IAsset from mv3d.resource.asset import Asset, AssetReference from mv3d.resource.local import LocalClassGeneratorAsset from mv3d.resource.local import LocalSoundAsset from mv3d.resource.url import URLClassGeneratorAsset, URLAsset, URLAssetError, \ URLShaderAsset from mv3d.resource.ogre3d import LocalOgreMaterialAsset from mv3d.resource.ogre3d import LocalOgreMeshAsset from mv3d.resource.ogre3d import LocalOgreObjectAsset from mv3d.resource.ogre3d import URLOgreMaterialAsset from mv3d.resource.ogre3d import URLOgreObjectAsset from mv3d.resource.url import URLImageAsset from mv3d.resource.url import URLFileAsset from mv3d.test.client import theRenderer, WithOgreRenderer, noOgre from mv3d.server.persist import SQLiteStore from mv3d.resource.panda import URLPandaMeshAsset, LocalPandaMeshAsset try: from ogre.renderer import OGRE as ogre except ImportError: pass class withStore(TestCase): """ Test with a datastore in a temp dir """ def setUp(self): self.store = SQLiteStore() return self.store.open() def tearDown(self): return self.store.close() class FakeAssetClient(object): """ A fake asset client. """ def __init__(self, assets): self.assets = assets @inlineCallbacks def acquireAsset(self, aid, downloadList, **_kw): asset = self.assets[aid] yield asset.acquireDependencies(downloadList=downloadList) returnValue(asset) class GenericAssetTests: """ Mixin for generic asset tests """ theClass = None def test_construct(self): """ Test constructing the asset """ self.theClass() def test_addDepends(self): """ Test adding dependencies """ l = self.theClass() l.addDependency((1, 1)) @inlineCallbacks def test_circularDeps(self): """ Assets that have themselves in their dependency list should raise an error """ asset = self.theClass() asset.aid = 1 asset2 = self.theClass() asset2.aid = 2 asset.parent = FakeAssetClient({2:asset2}) asset.addDependency(2) deps = yield asset.acquireDependencies() self.assertEqual(len(deps), 1) asset.addDependency(1) try: yield asset.acquireDependencies() except ValueError: pass else: self.fail("ValueError not raised.") self.flushLoggedErrors(ValueError) @inlineCallbacks def test_circularDepsMultiLevel(self): """ Assets that have a loop in their dependencies should raise an error """ asset = self.theClass() asset.aid = 1 asset2 = self.theClass() asset2.aid = 2 asset.parent = FakeAssetClient({2:asset2, 1:asset}) asset2.parent = asset.parent asset.addDependency(2) asset2.addDependency(1) try: yield asset.acquireDependencies() except FirstError: pass except ValueError: pass else: self.fail("FirstError not raised.") self.flushLoggedErrors(ValueError, FirstError) def test_interface(self): """ Test the IAsset interface """ verifyClass(IAsset, self.theClass) class LocalClassGeneratorAssetTests(withDataStore, GenericAssetTests): """ Test the local class generator asset """ theClass = LocalClassGeneratorAsset class LocalOgreMaterialAssetTests(withDataStore, GenericAssetTests): """ Test the local class generator asset """ theClass = LocalOgreMaterialAsset class LocalOgreMeshAssetTest(withDataStore, GenericAssetTests): """ Test the local class generator asset """ theClass = LocalOgreMeshAsset class LocalOgreObjectAssetTest(withDataStore, GenericAssetTests): """ Test the local class generator asset """ theClass = LocalOgreObjectAsset class LocalSoundAssetTests(withDataStore, GenericAssetTests): """ Test the local class generator asset """ theClass = LocalSoundAsset class URLClassGeneratorAssetTests(withDataStore, GenericAssetTests): """ Test the local class generator asset """ theClass = URLClassGeneratorAsset class URLOgreShaderAssetTests(withDataStore, GenericAssetTests): """ Test the url shader asset """ theClass = URLShaderAsset class URLOgreMaterialAssetTests(WithOgreRenderer, withStore, GenericAssetTests): """ Test the local class generator asset """ theClass = URLOgreMaterialAsset def setUp(self): """ call same on parent classes """ URLAsset.useMV3DPath = False WithOgreRenderer.setUp(self) withStore.setUp(self) def tearDown(self): """ call same on parent classes """ WithOgreRenderer.tearDown(self) withStore.tearDown(self) URLAsset.useMV3DPath = True def test_saveLoad(self): """ Save and load from store """ fdir = self.mktemp() if not os.path.exists(fdir): os.makedirs(fdir) fname = os.path.join(fdir, "store") store = SQLiteStore() store.open(fname) asset = self.theClass() asset.aid = (0, 0) asset.basedir = "/foo/bar" asset.setURL(u"http://download.mv3d.com/resources/materials/scripts/terrain.material") asset.setMaterialName("Material/TerrainTest") asset.setLocalFile(["materials", "scripts", "terrain.material"]) asset.addDependency((0, 4)) asset.addDependency((0, 5)) asset.addDependency((0, 6)) asset.addDependency((0, 7)) asset.grantPermission("read", "all") asset.grantPermission("reference", "all") asset.save(store) store.close() store.open(fname) self.theClass._cache = {} asset2 = self.theClass.get(store) self.assertNotIdentical(asset, asset2) self.assertEqual(asset2.aid, (0, 0)) self.assertEqual(asset2.basedir, "/foo/bar") self.assertEqual(asset2.localfile, ["materials", "scripts", "terrain.material"]) self.assertEqual(asset2.url, u"http://download.mv3d.com/resources/materials/scripts/terrain.material") def test_readyAsset(self): """ Test readying the asset """ tdir = self.mktemp() os.makedirs(os.path.join(tdir, "Group0")) tfile = open(os.path.join(tdir, "Group0", "test.material"), "w") tfile.write("""material SOLID/TEX/bark23.jpg { technique { pass { texture_unit { texture bark23.jpg } } } }""") tfile.close() asset = self.theClass() asset.aid = (0, 0) asset.basedir = tdir asset.materialname = "SOLID/TEX/bark23.jpg" asset.localfile = ["test.material"] asset.readyAsset() self.assertEqual(asset.readied, 1) # self.failUnless(ogre.ResourceGroupManager.getSingleton( # ).resourceExists("General", "test.material")) self.failUnless(ogre.MaterialManager.getSingleton( ).resourceExists("SOLID/TEX/bark23.jpg")) if theRenderer is None: test_readyAsset.skip = noOgre class URLOgreObjectAssetTests(withDataStore, GenericAssetTests): """ Test the local class generator asset """ theClass = URLOgreObjectAsset class URLImageAssetTests(withDataStore, GenericAssetTests): """ Test the local class generator asset """ theClass = URLImageAsset class URLFileAssetTests(withDataStore, GenericAssetTests): """ Test the local class generator asset """ theClass = URLFileAsset class TestURLPandaMeshAsset(withDataStore, GenericAssetTests): """ Test the url panda mesh asset """ theClass = URLPandaMeshAsset class TestLocalPandaMeshAsset(withDataStore, GenericAssetTests): """ Test the local panda mesh asset """ theClass = LocalPandaMeshAsset class AssetTests(TestCase): """ Test the asset class """ def setUp(self): self.store = SQLiteStore() self.store.open() def test_Constructor(self): """ You need to add a docstring here ! """ t = Asset() assert t.aid is None assert t.name == "" assert t.author == "" assert t.copyright == "" assert t.license == "" assert t.description == "" assert t.revisor == "" assert t.comment == "" assert t.asset is None def test_retrieveById(self): """ Test using the aid index in the store """ a = Asset() a.aid = (1, 23) a.save(self.store) a2 = Asset() a2.aid = (2, 23) a2.save(self.store) r = Asset.query(self.store, Asset.aid == (1, 23)) self.assertEqual(len(r), 1) self.assertEqual(r[0].aid, (1, 23)) class FakeURLAsset(Asset, URLAsset): _schemaVersion = 1 iid = (1, 2) useMV3DPath = False def getID(self): return self.iid class FakeAssetService: name = "George" def __init__(self): self.parent = self def log(self, *a, **kw): pass def getLocalService(self, _interface): return self def search(self, gid, cls, _query, onlyReturnIDs=False): return [(gid, 123)] def getAsset(self, aid): asset = Asset() asset.aid = aid asset.name = "Foo" return asset class TopLevel(Resource): def __init__(self, children): Resource.__init__(self) for k, v in children.items(): self.putChild(k, v) class ChildDoc(Resource): def __init__(self, text): Resource.__init__(self) self.text = text def render(self, request): return self.text class WithSimpleWebServer(TestCase): """ A test case that also has a web server """ resourceText = "foo foo foo bar bar bar" def setUp(self): site = TopLevel({"foo.txt":ChildDoc(self.resourceText)}) self.server = reactor.listenTCP(8889, Site(site)) #@UndefinedVariable def tearDown(self): return self.server.stopListening() class URLAssetTests(WithSimpleWebServer): """ Test url asset functionality """ def setUp(self): URLAsset.useMV3DPath = False WithSimpleWebServer.setUp(self) self.tempdir = self.mktemp() def tearDown(self): dfrd = WithSimpleWebServer.tearDown(self) URLAsset.useMV3DPath = True return dfrd def test_getFullPath(self): """ Test getting the full path of an asset """ u = FakeURLAsset() u.localfile = ("hello", "my", "name", "is.py") self.assertEqual(u.getFullPath(), os.path.join("Extern", "Group1", "hello", "my", "name")) def test_getLocalFile(self): """ Test getting the local file of an asset """ u = FakeURLAsset() u.localfile = ("hello", "my", "name", "is.py") self.assertEqual(u.getLocalFile(), os.path.join("hello", "my", "name", "is.py")) def test_getFullFile(self): """ Test getting the full local file of an asset """ u = FakeURLAsset() u.localfile = ("hello", "my", "name", "is.py") self.assertEqual(u.getFullFile(), os.path.abspath(os.path.join("Extern", "Group1", "hello", "my", "name", "is.py"))) @inlineCallbacks def test_acquireAsset(self): """ Test getting the asset via HTTP """ u = FakeURLAsset() u.basedir = self.tempdir u.localfile = ("test.txt",) u.parent = FakeAssetService() u.url = "http://localhost:8889/foo.txt" yield u.urlAcquireAsset() f = open(os.path.join(self.tempdir, "Group1", u.localfile[0])) data = f.read() f.close() self.assertEqual(data, self.resourceText) @inlineCallbacks def test_acquireAssetNoFilename(self): """ Test that an assertion is made if an asset with no filename is downloaded """ u = FakeURLAsset() u.parent = FakeAssetService() u.url = "http://localhost:8889/foo.txt" u.basedir = self.tempdir u.localfile = [""] try: yield u.urlAcquireAsset() self.fail("ValueError not raised!") except ValueError: pass @inlineCallbacks def test_acquireAssetUnicode(self): """ Test getting the asset via HTTP when the url is in unicode """ u = FakeURLAsset() u.basedir = self.tempdir u.localfile = (u"test.txt",) u.parent = FakeAssetService() u.url = u"http://localhost:8889/foo.txt" yield u.urlAcquireAsset() f = open(os.path.join(self.tempdir, "Group1", u.localfile[0])) data = f.read() f.close() self.assertEqual(data, self.resourceText) @inlineCallbacks def test_acquireAsset404(self): """ Test getting the asset via HTTP where the file doesn't exist """ u = FakeURLAsset() u.basedir = self.tempdir u.localfile = ("test.txt",) u.parent = FakeAssetService() u.url = "http://localhost:8889/foot.txt" try: yield u.urlAcquireAsset() self.fail("Didn't raise URLAssetError") except URLAssetError: pass self.failIf(os.path.exists(os.path.join(self.tempdir, "Group1", u.localfile[0]))) class TestAssetReference(TestCase): """ Tests for the AssetReference class """ def test_fromAsset(self): """ Test creating from an actual asset. """ asset = Asset() asset.name = "Foo" asset.aid = (1, 2) ref = AssetReference.fromAsset(asset) self.assertEqual(ref.name, "Foo") self.assertEqual(ref.agid, 1) self.assertEqual(ref.aid, (1, 2)) @inlineCallbacks def test_retrieveID(self): """ Test the method that searches the asset service for the id of the asset it references. """ ref = AssetReference(0, "Foo") yield ref.retrieveID(FakeAssetService()) self.assertEqual(ref.aid, (0, 123)) @inlineCallbacks def test_retrieveName(self): """ Test method to retrieve the name of the asset when we only have the id. """ ref = AssetReference(None, None) ref.aid = (0, 123) yield ref.retrieveName(FakeAssetService()) self.assertEqual(ref.name, "Foo")