Skip to content

Commit

Permalink
Implement reflection-based DBC deserialization, as well as some initi…
Browse files Browse the repository at this point in the history
…al tests.
  • Loading branch information
Nihlus committed Sep 6, 2017
1 parent 81c65a4 commit 567d733
Show file tree
Hide file tree
Showing 20 changed files with 824 additions and 26 deletions.
3 changes: 3 additions & 0 deletions libwarcraft.Tests/Content/.gitignore
@@ -0,0 +1,3 @@
*.*
!*.md
!.gitignore
4 changes: 4 additions & 0 deletions libwarcraft.Tests/Content/README.md
@@ -0,0 +1,4 @@
This directory shall contain actual data files that are used to test the compliance of the library.
No files are included, and must be extracted from a legitimately owned and licensed copy of World of Warcraft.

Each directory in this directory shall map to a member of the `WarcraftVersion` enum.
68 changes: 68 additions & 0 deletions libwarcraft.Tests/Integration/DBC/DBCTestHelper.cs
@@ -0,0 +1,68 @@
using System;
using System.IO;
using NUnit.Framework;
using Warcraft.Core;
using Warcraft.DBC;
using Warcraft.DBC.Definitions;

namespace libwarcraft.Tests.Integration.DBC
{
public static class DBCTestHelper
{
public static DBC<T> LoadDatabase<T>(WarcraftVersion version, DatabaseName databaseName) where T : DBCRecord, new()
{
return new DBC<T>(version, GetDatabaseBytes(version, databaseName));
}

public static bool HasDatabaseFile(WarcraftVersion version, DatabaseName databaseName)
{
return File.Exists(GetDatabaseFilePath(version, databaseName));
}

public static byte[] GetDatabaseBytes(WarcraftVersion version, DatabaseName databaseName)
{
return File.ReadAllBytes(GetDatabaseFilePath(version, databaseName));
}

private static string GetDatabaseFilePath(WarcraftVersion version, DatabaseName databaseName)
{
var path = Path.Combine
(
TestContext.CurrentContext.WorkDirectory,
"Content",
version.ToString(),
"DBFilesClient",
$"{databaseName}.dbc"
);

return path;
}

/// <summary>
/// Converts a database name into a qualified type.
/// </summary>
/// <param name="databaseName">The enumerated name of the database,</param>
/// <returns>The type mapping to the database name.</returns>
public static Type GetRecordTypeFromDatabaseName(DatabaseName databaseName)
{
return Type.GetType($"Warcraft.DBC.Definitions.{databaseName}Record, libwarcraft");
}

/// <summary>
/// Gets the database name from a type.
/// </summary>
/// <param name="recordType">The type of the record.</param>
/// <returns>The enumerated database name.</returns>
/// <exception cref="ArgumentException">Thrown if the given type can't be resolved to a database name.</exception>
public static DatabaseName GetDatabaseNameFromRecordType(Type recordType)
{
string recordName = recordType.Name.Replace("Record", string.Empty);
if (Enum.TryParse(recordName, true, out DatabaseName databaseName))
{
return databaseName;
}

throw new ArgumentException("The given type could not be resolved to a database name.", nameof(recordType));
}
}
}
105 changes: 105 additions & 0 deletions libwarcraft.Tests/Integration/DBC/IO/RecordDeserializationTests.cs
@@ -0,0 +1,105 @@
using System.IO;
using libwarcraft.Tests.Reflection;
using NUnit.Framework;
using Warcraft.Core;
using Warcraft.Core.Extensions;
using Warcraft.Core.Reflection.DBC;

namespace libwarcraft.Tests.Integration.DBC.IO
{
[TestFixture]
public class RecordDeserializationTests
{
private readonly byte[] TestDBCRecordBytesClassic =
{
1, 0, 0, 0, // ID
1, 0, 0, 0, // TestSimpleField
2, 0, 0, 0, // TestAddedAndRemovedField
6, 0, 0, 0, // TestForeignKeyField
};

private readonly byte[] TestDBCRecordBytesWrath =
{
1, 0, 0, 0, // ID
1, 0, 0, 0, // TestSimpleField
2, 0, 0, 0, // TestAddedAndRemovedField
6, 0, 0, 0, // TestForeignKeyField
4, 0, 0, 0, // TestNewFieldInWrath
};

private readonly byte[] TestDBCRecordBytesCata =
{
1, 0, 0, 0, // ID
1, 0, 0, 0, // TestSimpleField
6, 0, 0, 0, // TestForeignKeyField
4, 0, 0, 0, // TestNewFieldInWrath
};

[Test]
public void DeserializingTestDBCRecordSetsThePropertiesToTheCorrectValues()
{
var testVersion = WarcraftVersion.Classic;

TestDBCRecord record = new TestDBCRecord();
record.Version = testVersion;

using (var ms = new MemoryStream(this.TestDBCRecordBytesClassic))
{
using (var br = new BinaryReader(ms))
{
DBCReflection.DeserializeRecord(br, record, testVersion);
}
}

Assert.AreEqual(1, record.ID);
Assert.AreEqual(1, record.TestSimpleField);
Assert.AreEqual(2, record.TestAddedAndRemovedField);
Assert.AreEqual(6, record.TestForeignKeyField.Key);
}

[Test]
public void DeserializingTestDBCRecordSetsThePropertiesToTheCorrectValuesForAddedFields()
{
var testVersion = WarcraftVersion.Wrath;

TestDBCRecord record = new TestDBCRecord();
record.Version = testVersion;

using (var ms = new MemoryStream(this.TestDBCRecordBytesWrath))
{
using (var br = new BinaryReader(ms))
{
DBCReflection.DeserializeRecord(br, record, testVersion);
}
}

Assert.AreEqual(1, record.ID);
Assert.AreEqual(1, record.TestSimpleField);
Assert.AreEqual(2, record.TestAddedAndRemovedField);
Assert.AreEqual(6, record.TestForeignKeyField.Key);
Assert.AreEqual(4, record.TestNewFieldInWrath);
}

[Test]
public void DeserializingTestDBCRecordSetsThePropertiesToTheCorrectValuesForRemovedFields()
{
var testVersion = WarcraftVersion.Cataclysm;

TestDBCRecord record = new TestDBCRecord();
record.Version = testVersion;

using (var ms = new MemoryStream(this.TestDBCRecordBytesCata))
{
using (var br = new BinaryReader(ms))
{
DBCReflection.DeserializeRecord(br, record, testVersion);
}
}

Assert.AreEqual(1, record.ID);
Assert.AreEqual(1, record.TestSimpleField);
Assert.AreEqual(6, record.TestForeignKeyField.Key);
Assert.AreEqual(4, record.TestNewFieldInWrath);
}
}
}
132 changes: 132 additions & 0 deletions libwarcraft.Tests/Integration/DBC/Vanilla/RecordLoadingTests.cs
@@ -0,0 +1,132 @@
using System;
using System.Linq;
using NUnit.Framework;
using Warcraft.Core;
using Warcraft.DBC;
using Warcraft.DBC.Definitions;

namespace libwarcraft.Tests.Integration.DBC.Vanilla
{
[TestFixture]
public class RecordLoadingTests
{
private const WarcraftVersion Version = WarcraftVersion.Classic;

private static void TestLoadRecord<T>(WarcraftVersion version) where T : DBCRecord, new()
{
var databaseName = DBCTestHelper.GetDatabaseNameFromRecordType(typeof(T));
if (!DBCTestHelper.HasDatabaseFile(version, databaseName))
{
Assert.Ignore("Database file not present. Skipping.");
}

var database = DBCTestHelper.LoadDatabase<T>(version, databaseName);

try
{
database.First();
}
catch (ArgumentException e)
{
Assert.Fail($"Failed to read {databaseName}: {e}");
}
}

[Test]
public void TestLoadAnimationDataRecord()
{
TestLoadRecord<AnimationDataRecord>(Version);
}

[Test]
public void TestLoadCharHairGeosetsRecord()
{
TestLoadRecord<CharHairGeosetsRecord>(Version);
}

[Test]
public void TestLoadSoundAmbienceRecord()
{
TestLoadRecord<SoundAmbienceRecord>(Version);
}

[Test]
public void TestLoadCharSectionsRecord()
{
TestLoadRecord<CharSectionsRecord>(Version);
}

[Test]
public void TestLoadSoundEntriesRecord()
{
TestLoadRecord<SoundEntriesRecord>(Version);
}

[Test]
public void TestLoadCreatureDisplayInfoExtraRecord()
{
TestLoadRecord<CreatureDisplayInfoExtraRecord>(Version);
}

[Test]
public void TestLoadSoundProviderPreferences()
{
TestLoadRecord<SoundProviderPreferencesRecord>(Version);
}

[Test]
public void TestLoadCreatureDisplayInfoRecord()
{
TestLoadRecord<CreatureDisplayInfoRecord>(Version);
}

[Test]
public void TestLoadSpellRecord()
{
TestLoadRecord<SpellRecord>(Version);
}

[Test]
public void TestLoadCreatureModelDataRecord()
{
TestLoadRecord<CreatureModelDataRecord>(Version);
}

[Test]
public void TestLoadWMOAreaTableRecord()
{
TestLoadRecord<WMOAreaTableRecord>(Version);
}

[Test]
public void TestLoadLiquidObjectRecord()
{
TestLoadRecord<LiquidObjectRecord>(Version);
}

[Test]
public void TestLoadZoneIntroMusicTableRecord()
{
TestLoadRecord<ZoneIntroMusicTableRecord>(Version);
}

[Test]
public void TestLoadLiquidTypeRecord()
{
TestLoadRecord<LiquidTypeRecord>(Version);
}

[Test]
public void TestLoadZoneMusicRecord()
{
TestLoadRecord<ZoneMusicRecord>(Version);
}

[Test]
public void TestLoadMapRecord()
{
TestLoadRecord<MapRecord>(Version);
}

}
}

0 comments on commit 567d733

Please sign in to comment.