#region CPL License
/*
Nuclex Framework
Copyright (C) 2002-2011 Nuclex Development Labs
This library is free software; you can redistribute it and/or
modify it under the terms of the IBM Common Public License as
published by the IBM Corporation; either version 1.0 of the
License, or (at your option) any later version.
This library 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
IBM Common Public License for more details.
You should have received a copy of the IBM Common Public
License along with this library
*/
#endregion
#if UNITTEST
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using NUnit.Framework;
using Nuclex.Game.ContentCompressor;
using Nuclex.Graphics;
using Nuclex.Testing.Xna;
namespace Nuclex.Game.Content {
/// Unit test for the LZMA content manager class
[TestFixture]
internal class LzmaContentManagerTest {
#region class TempDirectoryKeeper
/// Creates and provides a temporary directory
private class TempDirectoryKeeper : IDisposable {
/// Initializes a new temp directory keeper
public TempDirectoryKeeper() {
this.tempFile = System.IO.Path.GetTempFileName();
try {
this.tempDir = System.IO.Path.ChangeExtension(this.tempFile, ".dir");
Directory.CreateDirectory(this.tempDir);
}
catch(Exception) {
File.Delete(this.tempFile);
}
}
/// Immediately releases all resources owned by the instance
public void Dispose() {
if(this.tempDir != null) {
Directory.Delete(this.tempDir, true);
this.tempDir = null;
}
if(this.tempFile != null) {
File.Delete(this.tempFile);
this.tempFile = null;
}
}
/// The full path to the temporary directory
public string Path {
get { return this.tempDir; }
}
/// Temporary file that has been created to get a unique name
private string tempFile;
/// Full path of the temporary directory
private string tempDir;
}
#endregion // class TempDirectoryKeeper
///
/// Verifies that the LZMA content manager can load assets out of
/// compressed files
///
[Test]
public void TestCompressedContentLoading() {
// Extract the .xnb test file for the unit test and compress it
{
string path = Path.Combine(this.tempDirectory.Path, "UnitTestEffect.xnb");
writeBytesToFile(
Resources.UnitTestResources.UnitTestEffect,
path
);
LzmaContentCompressor.CompressContentFile(path);
File.Delete(path);
}
// Now try to load the compressed file
using(
LzmaContentManager contentManager = new LzmaContentManager(
GraphicsDeviceServiceHelper.MakePrivateServiceProvider(
this.mockedGraphicsDeviceService
)
)
) {
contentManager.RootDirectory = this.tempDirectory.Path;
Effect effect = contentManager.Load("UnitTestEffect");
Assert.IsNotNull(effect);
}
}
///
/// Verifies that the LZMA content manager uses an uncompressed asset if
/// it is available in parallel to the compressed one
///
[Test]
public void TestCompressedContentReplacement() {
// If the replacement doesn't work, the test will load this file which,
// as the observant programmer might notice, contains 'Crap' :-)
writeBytesToFile(
new byte[] { (byte)'C', (byte)'r', (byte)'a', (byte)'p' },
Path.Combine(this.tempDirectory.Path, "UnitTestEffect.lzma")
);
// Write the real file the test should be loading
writeBytesToFile(
Resources.UnitTestResources.UnitTestEffect,
Path.Combine(this.tempDirectory.Path, "UnitTestEffect.xnb")
);
using(
LzmaContentManager contentManager = new LzmaContentManager(
GraphicsDeviceServiceHelper.MakePrivateServiceProvider(
this.mockedGraphicsDeviceService
)
)
) {
contentManager.RootDirectory = this.tempDirectory.Path;
// The .lzma file contains 'Crap' (literally :D), so if the content manager
// didn't see the replacement file, it would fall on its nose here!
Effect effect = contentManager.Load("UnitTestEffect");
Assert.IsNotNull(effect);
}
}
///
/// Verifies that the LZMA content manager can load assets out of
/// compressed packages
///
[Test]
public void TestPackagedContentLoading() {
// Extract the .xnb test file for the unit test and compress it
string packagePath = Path.Combine(this.tempDirectory.Path, "UnitTestEffect.package");
{
string filePath = Path.Combine(this.tempDirectory.Path, "UnitTestEffect.xnb");
writeBytesToFile(
Resources.UnitTestResources.UnitTestEffect,
filePath
);
LzmaPackageBuilder.Build(
packagePath, new LzmaPackageBuilder.PackageFile(filePath, "UnitTestEffect")
);
File.Delete(filePath);
}
using(
LzmaContentManager contentManager = new LzmaContentManager(
GraphicsDeviceServiceHelper.MakePrivateServiceProvider(
this.mockedGraphicsDeviceService
),
packagePath
)
) {
contentManager.RootDirectory = Path.GetDirectoryName(packagePath);
Effect effect = contentManager.Load("UnitTestEffect");
Assert.IsNotNull(effect);
}
}
///
/// Verifies that the LZMA content manager uses an uncompressed asset if
/// it is available even when though no package exists
///
[Test]
public void TestPackagedContentReplacement() {
// Extract the .xnb test file for the unit test and compress it
string packagePath = Path.Combine(this.tempDirectory.Path, "UnitTestEffect.package");
{
string filePath = Path.Combine(this.tempDirectory.Path, "UnitTestEffect.xnb");
// We will compress this nonsense file so that if the replacement isn't
// honored, the content manager will fail.
writeBytesToFile(
new byte[] { (byte)'C', (byte)'r', (byte)'a', (byte)'p' }, filePath
);
LzmaPackageBuilder.Build(
packagePath, new LzmaPackageBuilder.PackageFile(filePath, "UnitTestEffect")
);
File.Delete(filePath);
// Now write the replacement, which actually contains valid data
writeBytesToFile(
Resources.UnitTestResources.UnitTestEffect,
filePath
);
}
using(
LzmaContentManager contentManager = new LzmaContentManager(
GraphicsDeviceServiceHelper.MakePrivateServiceProvider(
this.mockedGraphicsDeviceService
),
packagePath
)
) {
contentManager.RootDirectory = this.tempDirectory.Path;
// This only works if the content manager loads the replacement instead
// of the packaged file
Effect effect = contentManager.Load("UnitTestEffect");
Assert.IsNotNull(effect);
}
}
///
/// Verifies that the LZMA content manager uses an uncompressed asset if
/// it is available even when though no package exists
///
[Test]
public void TestPackagedContentReplacementWhenNoPackageExists() {
string packagePath = Path.Combine(
this.tempDirectory.Path, "PackagedUnitTestEffect.package"
);
writeBytesToFile(
Resources.UnitTestResources.UnitTestEffect,
Path.Combine(this.tempDirectory.Path, "UnitTestEffect.xnb")
);
using(
LzmaContentManager contentManager = new LzmaContentManager(
GraphicsDeviceServiceHelper.MakePrivateServiceProvider(
this.mockedGraphicsDeviceService
),
packagePath
)
) {
contentManager.RootDirectory = this.tempDirectory.Path;
// The package doesn't even exist, but because replacement is allowed,
// no error should occur if the requested asset is available directly
Effect effect = contentManager.Load("UnitTestEffect");
Assert.IsNotNull(effect);
}
}
///
/// Tests whether the LZMA content manager cleans up any open file handles
/// when an exception occurs while the package is opened
///
[Test]
public void TestCleanupAfterException() {
string packagePath = Path.Combine(
this.tempDirectory.Path, "PackagedUnitTestEffect.package"
);
writeBytesToFile(BitConverter.GetBytes(-1), packagePath);
Assert.Throws(
delegate() {
using(
LzmaContentManager contentManager = new LzmaContentManager(
GraphicsDeviceServiceHelper.MakePrivateServiceProvider(
this.mockedGraphicsDeviceService
),
packagePath
)
) { }
}
);
// If the package is left open due to the exception, a follow-up error
// will happen in the Teardown() method.
}
///
/// Verifies that the right exception is thrown if a packaged does not exist
///
[Test]
public void TestThrowsOnMissingPackagedAsset() {
string packagePath = Path.Combine(
this.tempDirectory.Path, "PackagedUnitTestEffect.package"
);
using(
LzmaContentManager contentManager = new LzmaContentManager(
GraphicsDeviceServiceHelper.MakePrivateServiceProvider(
this.mockedGraphicsDeviceService
),
packagePath
)
) {
contentManager.RootDirectory = this.tempDirectory.Path;
Assert.Throws(
delegate() {
contentManager.Load("DoesNotExist");
}
);
}
}
///
/// Verifies that the LZMA content manager uses an uncompressed asset if
/// it is available even when though no package exists
///
[Test]
public void TestThrowOnMissingCompressedAsset() {
using(
LzmaContentManager contentManager = new LzmaContentManager(
GraphicsDeviceServiceHelper.MakePrivateServiceProvider(
this.mockedGraphicsDeviceService
)
)
) {
contentManager.RootDirectory = this.tempDirectory.Path;
Assert.Throws(
delegate() {
contentManager.Load("DoesNotExist");
}
);
}
}
/// Called before each test is run
[SetUp]
public void Setup() {
this.mockedGraphicsDeviceService = new MockedGraphicsDeviceService();
this.mockedGraphicsDeviceService.CreateDevice();
this.tempDirectory = new TempDirectoryKeeper();
}
/// Called after each test has run
[TearDown]
public void TearDown() {
if(this.tempDirectory != null) {
this.tempDirectory.Dispose();
this.tempDirectory = null;
}
if(this.mockedGraphicsDeviceService != null) {
this.mockedGraphicsDeviceService.DestroyDevice();
this.mockedGraphicsDeviceService = null;
}
}
/// Saves a bytes array into a file
/// Byte array that will be written to a file
/// Name of the file the byte array will be written to
private void writeBytesToFile(byte[] bytes, string path) {
using(
FileStream stream = new FileStream(
path, FileMode.Create, FileAccess.Write, FileShare.None
)
) {
stream.Write(bytes, 0, bytes.Length);
stream.Flush();
}
}
/// Mocked graphics device service used for unit testing
private MockedGraphicsDeviceService mockedGraphicsDeviceService;
/// Creates a temp directory and keeps it alive until disposed
private TempDirectoryKeeper tempDirectory;
}
} // namespace Nuclex.Game.Content
#endif // UNITTEST