Moved Wabbajack.Commons tests into Wabbajack.Commons.Test out of Wabbajack.Test. They all pass

This commit is contained in:
Timothy Baldridge 2020-03-25 22:25:48 -06:00
parent 006b045348
commit 51bad949ec
20 changed files with 457 additions and 459 deletions

View File

@ -20,10 +20,10 @@ namespace Compression.BSA.Test
[TestClass]
public class BSATests
{
private static string _stagingFolder = "NexusDownloads";
private static string _bsaFolder = "BSAs";
private static string _testDir = "BSA Test Dir";
private static string _tempDir = "BSA Temp Dir";
private static AbsolutePath _stagingFolder = ((RelativePath)"NexusDownloads").RelativeToEntryPoint();
private static AbsolutePath _bsaFolder = ((RelativePath)"BSAs").RelativeToEntryPoint();
private static AbsolutePath _testDir = ((RelativePath)"BSA Test Dir").RelativeToEntryPoint();
private static AbsolutePath _tempDir = ((RelativePath)"BSA Temp Dir").RelativeToEntryPoint();
public TestContext TestContext { get; set; }
@ -34,11 +34,8 @@ namespace Compression.BSA.Test
{
Queue = new WorkQueue();
Utils.LogMessages.Subscribe(f => testContext.WriteLine(f.ShortDescription));
if (!Directory.Exists(_stagingFolder))
Directory.CreateDirectory(_stagingFolder);
if (!Directory.Exists(_bsaFolder))
Directory.CreateDirectory(_bsaFolder);
_stagingFolder.DeleteDirectory();
_bsaFolder.DeleteDirectory();
var modIDs = new[]
{
@ -53,22 +50,21 @@ namespace Compression.BSA.Test
await Task.WhenAll(modIDs.Select(async (info) =>
{
var filename = await DownloadMod(info);
var folder = Path.Combine(_bsaFolder, info.Item1.ToString(), info.Item2.ToString());
if (!Directory.Exists(folder))
Directory.CreateDirectory(folder);
var folder = _bsaFolder.Combine(info.Item1.ToString(), info.Item2.ToString());
folder.CreateDirectory();
await FileExtractor.ExtractAll(Queue, filename, folder);
}));
}
private static async Task<string> DownloadMod((Game, int) info)
private static async Task<AbsolutePath> DownloadMod((Game, int) info)
{
using var client = await NexusApiClient.Get();
var results = await client.GetModFiles(info.Item1, info.Item2);
var file = results.files.FirstOrDefault(f => f.is_primary) ??
results.files.OrderByDescending(f => f.uploaded_timestamp).First();
var src = Path.Combine(_stagingFolder, file.file_name);
var src = _stagingFolder.Combine(file.file_name);
if (File.Exists(src)) return src;
if (src.Exists) return src;
var state = new NexusDownloader.State
{
@ -82,41 +78,38 @@ namespace Compression.BSA.Test
public static IEnumerable<object[]> BSAs()
{
return Directory.EnumerateFiles(_bsaFolder, "*", DirectoryEnumerationOptions.Recursive)
.Where(f => Consts.SupportedBSAs.Contains(Path.GetExtension(f)))
return _bsaFolder.EnumerateFiles()
.Where(f => Consts.SupportedBSAs.Contains(f.Extension))
.Select(nm => new object[] {nm});
}
[TestMethod]
[DataTestMethod]
[DynamicData(nameof(BSAs), DynamicDataSourceType.Method)]
public async Task BSACompressionRecompression(string bsa)
public async Task BSACompressionRecompression(AbsolutePath bsa)
{
TestContext.WriteLine($"From {bsa}");
TestContext.WriteLine("Cleaning Output Dir");
if (Directory.Exists(_tempDir)) Utils.DeleteDirectory(_tempDir);
Directory.CreateDirectory(_tempDir);
_tempDir.DeleteDirectory();
_tempDir.CreateDirectory();
TestContext.WriteLine($"Reading {bsa}");
string tempFile = Path.Combine("tmp.bsa");
var size = File.GetSize(bsa);
var tempFile = ((RelativePath)"tmp.bsa").RelativeToEntryPoint();
var size = bsa.Size;
using (var a = BSADispatch.OpenRead(bsa))
{
await a.Files.PMap(Queue, file =>
{
var absName = Path.Combine(_tempDir, file.Path);
var absName = _tempDir.Combine(file.Path);
ViaJson(file.State);
if (!Directory.Exists(Path.GetDirectoryName(absName)))
Directory.CreateDirectory(Path.GetDirectoryName(absName));
using (var fs = File.Open(absName, FileMode.Create))
absName.Parent.CreateDirectory();
using (var fs = absName.Create())
{
file.CopyDataTo(fs);
}
Assert.AreEqual(file.Size, new FileInfo(absName).Length);
Assert.AreEqual(file.Size, absName.Size);
});
Console.WriteLine($"Building {bsa}");
@ -125,8 +118,8 @@ namespace Compression.BSA.Test
{
var streams = await a.Files.PMap(Queue, file =>
{
var absPath = Path.Combine(_tempDir, file.Path);
var str = File.OpenRead(absPath);
var absPath = _tempDir.Combine(file.Path);
var str = absPath.OpenRead();
w.AddFile(ViaJson(file.State), str);
return str;
});

View File

@ -1,17 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Wabbajack.Common;
using Xunit;
namespace Wabbajack.Test
namespace Wabbajack.Common.Test
{
[TestClass]
public class AsyncLockTests
{
[TestMethod]
[Fact]
public async Task Typical()
{
var asyncLock = new AsyncLock();
@ -29,20 +24,20 @@ namespace Wabbajack.Test
await Task.Delay(200);
using (await asyncLock.Wait())
{
Assert.IsTrue(firstRun);
Assert.True(firstRun);
}
});
await Task.WhenAll(first, second);
}
[TestMethod]
[Fact]
public async Task Exception()
{
var asyncLock = new AsyncLock();
bool firstRun = false;
bool secondRun = false;
// Throw exception inside a lock
await Assert.ThrowsExceptionAsync<Exception>(() =>
await Assert.ThrowsAsync<Exception>(() =>
{
return Task.Run(async () =>
{
@ -62,7 +57,7 @@ namespace Wabbajack.Test
await Task.Delay(200);
using (await asyncLock.Wait())
{
Assert.IsTrue(firstRun);
Assert.True(firstRun);
secondRun = true;
}
}),

View File

@ -1,18 +1,14 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Wabbajack.Common;
using Xunit;
namespace Wabbajack.Test
namespace Wabbajack.Common.Test
{
[TestClass]
public class EncryptedDataTests
{
[TestMethod]
[Fact]
public async Task CanDetectNewEncryptedData()
{
var test_string = Guid.NewGuid().ToString();
@ -28,7 +24,7 @@ namespace Wabbajack.Test
test_string.ToEcryptedJson(test_string);
await Task.Delay(100);
CollectionAssert.Contains(data, test_string);
Assert.Contains(test_string, data);
}

View File

@ -1,18 +1,17 @@
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Xunit;
namespace Wabbajack.Test
namespace Wabbajack.Common.Test
{
[TestClass]
public class HttpClientTests
{
[TestMethod]
[Fact]
public async Task DoesntReuseHttpMessages()
{
var client = new Common.Http.Client();
// If we reuse the HTTP message this will throw a invalid operation exception
await Assert.ThrowsExceptionAsync<HttpRequestException>(async () => await client.GetAsync("http://blerg.blaz.bloz.buz"));
await Assert.ThrowsAsync<HttpRequestException>(async () => await client.GetAsync("http://blerg.blaz.bloz.buz"));
}
}
}

View File

@ -1,25 +1,23 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Wabbajack.Common;
using Xunit;
namespace Wabbajack.Test
namespace Wabbajack.Common.Test
{
[TestClass]
public class IniTests
{
[TestMethod]
[Fact]
public void TestByteArrayParsing()
{
Assert.AreEqual("bar", @"[General]
Assert.Equal("bar", @"[General]
foo = bar".LoadIniString().General.foo);
Assert.AreEqual("baz\\bar", @"[General]
Assert.Equal("baz\\bar", @"[General]
foo = baz\\bar".LoadIniString().General.foo);
Assert.AreEqual("bar", @"[General]
Assert.Equal("bar", @"[General]
foo = @ByteArray(bar)".LoadIniString().General.foo);
Assert.AreEqual("foo\\h̴̹͚̎é̶̘͙̐l̶͕̔͑p̴̯̋͂m̶̞̮͘͠e̸͉͙͆̄\\baz", @"[General]
Assert.Equal("foo\\h̴̹͚̎é̶̘͙̐l̶͕̔͑p̴̯̋͂m̶̞̮͘͠e̸͉͙͆̄\\baz", @"[General]
foo = @ByteArray(foo\\\x68\xcc\xb4\xcc\x8e\xcc\xb9\xcd\x9a\x65\xcc\xb6\xcd\x81\xcc\x90\xcc\x98\xcd\x99\x6c\xcc\xb6\xcc\x94\xcd\x91\xcd\x95\x70\xcc\xb4\xcc\x8b\xcd\x82\xcc\xaf\x6d\xcc\xb6\xcd\x98\xcd\xa0\xcc\x9e\xcc\xae\x65\xcc\xb8\xcd\x86\xcc\x84\xcd\x89\xcd\x99\\baz)".LoadIniString().General.foo);
}

View File

@ -0,0 +1,31 @@
using System.Threading.Tasks;
using Alphaleonis.Win32.Filesystem;
using Xunit;
namespace Wabbajack.Common.Test
{
public class MiscTests
{
[Fact]
public void TestDiskSpeed()
{
using (var queue = new WorkQueue())
{
var speed = Utils.TestDiskSpeed(queue, @".\");
}
}
[Fact]
public async Task TestHash()
{
var testFile = ((RelativePath)"text.data").RelativeToEntryPoint();
const string data = "Cheese for Everyone!";
await testFile.WriteAllTextAsync(data);
File.WriteAllText("test.data", data);
Assert.Equal(Hash.FromBase64("eSIyd+KOG3s="), testFile.FileHashCached());
Assert.True(Utils.TryGetHashCache(testFile, out var fileHash));
Assert.Equal(Hash.FromBase64("eSIyd+KOG3s="), fileHash);
Assert.NotEqual("eSIyd+KOG3s=", await testFile.WithExtension(Consts.HashFileExtension).ReadAllTextAsync());
}
}
}

View File

@ -0,0 +1,206 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace Wabbajack.Common.Test
{
public class PMapTests
{
const int TypicalThreadCount = 6;
const int TypicalDelayMS = 50;
const int TimeoutSeconds = 15;
[Fact]
public async Task Typical_Action()
{
using var queue = new WorkQueue(TypicalThreadCount);
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var output = new List<int>();
var workTask = Utils.PMap(Enumerable.Range(0, TypicalThreadCount * 2), queue, (item) =>
{
Assert.True(WorkQueue.WorkerThread);
Thread.Sleep(TypicalDelayMS);
lock (output)
{
output.Add(item);
}
});
await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.True(input.SequenceEqual(output.OrderBy(i => i)));
}
[Fact]
public async Task Typical_Func()
{
using var queue = new WorkQueue(TypicalThreadCount);
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var workTask = Utils.PMap(Enumerable.Range(0, TypicalThreadCount * 2), queue, (item) =>
{
Assert.True(WorkQueue.WorkerThread);
Thread.Sleep(TypicalDelayMS);
return item.ToString();
});
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.True(input.Select(i => i.ToString()).SequenceEqual(results));
}
[Fact]
public async Task Typical_Task()
{
using var queue = new WorkQueue(TypicalThreadCount);
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var output = new List<int>();
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
.PMap(queue, async (item) =>
{
Assert.True(WorkQueue.WorkerThread);
await Task.Delay(TypicalDelayMS);
lock (output)
{
output.Add(item);
}
});
await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.True(input.SequenceEqual(output.OrderBy(i => i)));
}
[Fact]
public async Task Typical_TaskReturn()
{
using var queue = new WorkQueue(TypicalThreadCount);
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
.PMap(queue, async (item) =>
{
Assert.True(WorkQueue.WorkerThread);
await Task.Delay(TypicalDelayMS);
return item.ToString();
});
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.True(input.Select(i => i.ToString()).SequenceEqual(results));
}
[Fact]
public async Task NestedAction()
{
using var queue = new WorkQueue(TypicalThreadCount);
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
var output = new List<int>();
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
.PMap(queue, async (item) =>
{
Assert.True(WorkQueue.WorkerThread);
await Enumerable.Range(item * 100, TypicalThreadCount * 2)
.PMap(queue, async (subItem) =>
{
Assert.True(WorkQueue.WorkerThread);
Thread.Sleep(TypicalDelayMS);
lock (output)
{
output.Add(subItem);
}
});
});
await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.True(inputConstructedResults.SequenceEqual(output.OrderBy(i => i)));
}
[Fact]
public async Task Nested_Func()
{
using var queue = new WorkQueue(TypicalThreadCount);
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
.PMap(queue, async (item) =>
{
Assert.True(WorkQueue.WorkerThread);
return await Utils.PMap(Enumerable.Range(item * 100, TypicalThreadCount * 2), queue, (subItem) =>
{
Assert.True(WorkQueue.WorkerThread);
Thread.Sleep(TypicalDelayMS);
return subItem;
});
});
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.True(inputConstructedResults.SequenceEqual(results.SelectMany(i => i)));
}
[Fact]
public async Task Nested_Task()
{
using var queue = new WorkQueue(TypicalThreadCount);
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
var output = new List<int>();
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
.PMap(queue, async (item) =>
{
Assert.True(WorkQueue.WorkerThread);
await Enumerable.Range(item * 100, TypicalThreadCount * 2)
.PMap(queue, async (subItem) =>
{
Assert.True(WorkQueue.WorkerThread);
await Task.Delay(TypicalDelayMS);
lock (output)
{
output.Add(subItem);
}
});
});
await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.True(inputConstructedResults.SequenceEqual(output.OrderBy(i => i)));
}
[Fact]
public async Task Nested_TaskReturn()
{
using var queue = new WorkQueue(TypicalThreadCount);
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
.PMap(queue, async (item) =>
{
Assert.True(WorkQueue.WorkerThread);
return await Enumerable.Range(item * 100, TypicalThreadCount * 2)
.PMap(queue, async (subItem) =>
{
Assert.True(WorkQueue.WorkerThread);
await Task.Delay(TypicalDelayMS);
return subItem;
});
});
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.True(inputConstructedResults.SequenceEqual(results.SelectMany(i => i)));
}
[Fact]
public async Task Nested_BackgroundThreadsInvolved()
{
using var queue = new WorkQueue(TypicalThreadCount);
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
.PMap(queue, async (item) =>
{
Assert.True(WorkQueue.WorkerThread);
return await Enumerable.Range(item * 100, TypicalThreadCount * 2)
.PMap(queue, async (subItem) =>
{
return await Task.Run(async () =>
{
Assert.True(WorkQueue.WorkerThread);
await Task.Delay(TypicalDelayMS);
return subItem;
});
});
});
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.True(inputConstructedResults.SequenceEqual(results.SelectMany(i => i)));
}
}
}

View File

@ -1,29 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Xunit;
namespace Wabbajack.Test
namespace Wabbajack.Common.Test
{
[TestClass]
public class TaskExtTests
{
[TestMethod]
[Fact]
public async Task TimeoutButContinue_Typical()
{
bool timedOut = false;
await Task.Delay(100).TimeoutButContinue(TimeSpan.FromSeconds(1), () => timedOut = true);
Assert.IsFalse(timedOut);
Assert.False(timedOut);
}
[TestMethod]
[Fact]
public async Task TimeoutButContinue_TimedOut()
{
bool timedOut = false;
await Task.Delay(300).TimeoutButContinue(TimeSpan.FromMilliseconds(100), () => timedOut = true);
Assert.IsTrue(timedOut);
Assert.True(timedOut);
}
}
}

View File

@ -0,0 +1,24 @@
using System;
namespace Wabbajack.Common.Test
{
public static class TestUtils
{
private static Random _random = new Random();
public static byte[] RandomData(int? size = null, int maxSize = 1024)
{
if (size == null)
size = _random.Next(1, maxSize);
var arr = new byte[(int) size];
_random.NextBytes(arr);
return arr;
}
public static object RandomOne(params object[] opts)
{
return opts[_random.Next(0, opts.Length)];
}
}
}

View File

@ -2,33 +2,29 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Wabbajack.Common;
using Xunit;
namespace Wabbajack.Test
namespace Wabbajack.Common.Test
{
[TestClass]
public class UtilsTests
{
[TestMethod]
[Fact]
public void IsInPathTests()
{
Assert.IsTrue("c:\\foo\\bar.exe".IsInPath("c:\\foo"));
Assert.IsFalse("c:\\foo\\bar.exe".IsInPath("c:\\fo"));
Assert.IsTrue("c:\\Foo\\bar.exe".IsInPath("c:\\foo"));
Assert.IsTrue("c:\\foo\\bar.exe".IsInPath("c:\\Foo"));
Assert.IsTrue("c:\\foo\\bar.exe".IsInPath("c:\\fOo"));
Assert.IsTrue("c:\\foo\\bar.exe".IsInPath("c:\\foo\\"));
Assert.IsTrue("c:\\foo\\bar\\".IsInPath("c:\\foo\\"));
Assert.True("c:\\foo\\bar.exe".IsInPath("c:\\foo"));
Assert.False("c:\\foo\\bar.exe".IsInPath("c:\\fo"));
Assert.True("c:\\Foo\\bar.exe".IsInPath("c:\\foo"));
Assert.True("c:\\foo\\bar.exe".IsInPath("c:\\Foo"));
Assert.True("c:\\foo\\bar.exe".IsInPath("c:\\fOo"));
Assert.True("c:\\foo\\bar.exe".IsInPath("c:\\foo\\"));
Assert.True("c:\\foo\\bar\\".IsInPath("c:\\foo\\"));
}
[TestMethod]
[DataTestMethod]
[DynamicData(nameof(PatchData), DynamicDataSourceType.Method)]
[Theory]
[ClassData(typeof(PatchData))]
public async Task DiffCreateAndApply(byte[] src, byte[] dest, DiffMethod method)
{
await using var ms = new MemoryStream();
@ -51,7 +47,7 @@ namespace Wabbajack.Test
var patch = ms.ToArray();
await using var resultStream = new MemoryStream();
Utils.ApplyPatch(new MemoryStream(src), () => new MemoryStream(patch), resultStream);
CollectionAssert.AreEqual(dest, resultStream.ToArray());
Assert.Equal(dest, resultStream.ToArray());
}
@ -61,10 +57,18 @@ namespace Wabbajack.Test
BSDiff,
OctoDiff
}
public static IEnumerable<object[]> PatchData()
public class PatchData : TheoryData<byte[], byte[], DiffMethod>
{
var maxSize = 1024 * 1024 * 8;
return Enumerable.Range(0, 10).Select(x => new[] {TestUtils.RandomData(maxSize:maxSize), TestUtils.RandomData(maxSize:maxSize), TestUtils.RandomeOne(DiffMethod.Default, DiffMethod.OctoDiff, DiffMethod.BSDiff)});
public PatchData()
{
var maxSize = 64;
Enumerable.Range(0, 10).Do(x =>
{
Add(TestUtils.RandomData(maxSize: maxSize), TestUtils.RandomData(maxSize: maxSize),
(DiffMethod)TestUtils.RandomOne(DiffMethod.Default, DiffMethod.OctoDiff, DiffMethod.BSDiff));
});
}
}
}
}

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Platforms>x64</Platforms>
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.console" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Wabbajack.Common\Wabbajack.Common.csproj" />
</ItemGroup>
</Project>

View File

@ -1,17 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Wabbajack.Common;
using Xunit;
namespace Wabbajack.Test
namespace Wabbajack.Common.Test
{
[TestClass]
public class WorkQueueTests
{
#region DynamicNumThreads
@ -20,144 +16,144 @@ namespace Wabbajack.Test
const int Small = 4;
public TimeSpan PollMS => TimeSpan.FromSeconds(1);
[TestMethod]
[Fact]
public void DynamicNumThreads_Typical()
{
using (var queue = new WorkQueue())
{
Assert.AreEqual(Environment.ProcessorCount, queue.DesiredNumWorkers);
Assert.AreEqual(Environment.ProcessorCount, queue._tasks.Count);
Assert.Equal(Environment.ProcessorCount, queue.DesiredNumWorkers);
Assert.Equal(Environment.ProcessorCount, queue._tasks.Count);
}
}
[TestMethod]
[Fact]
public void DynamicNumThreads_Increased()
{
var subj = new BehaviorSubject<int>(Small);
using (var queue = new WorkQueue(subj))
{
Assert.AreEqual(Small, queue.DesiredNumWorkers);
Assert.AreEqual(Small, queue._tasks.Count);
Assert.Equal(Small, queue.DesiredNumWorkers);
Assert.Equal(Small, queue._tasks.Count);
subj.OnNext(Large);
Assert.AreEqual(Large, queue.DesiredNumWorkers);
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Large, queue.DesiredNumWorkers);
Assert.Equal(Large, queue._tasks.Count);
}
}
[TestMethod]
[Fact]
public void DynamicNumThreads_EmptyObs()
{
using (var queue = new WorkQueue(Observable.Empty<int>()))
{
Assert.AreEqual(0, queue.DesiredNumWorkers);
Assert.AreEqual(0, queue._tasks.Count);
Assert.Equal(0, queue.DesiredNumWorkers);
Assert.Equal(0, queue._tasks.Count);
}
}
[TestMethod]
[Fact]
public async Task DynamicNumThreads_Decreased()
{
var subj = new BehaviorSubject<int>(Large);
using (var queue = new WorkQueue(subj))
{
Assert.AreEqual(Large, queue.DesiredNumWorkers);
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Large, queue.DesiredNumWorkers);
Assert.Equal(Large, queue._tasks.Count);
subj.OnNext(Small);
Assert.AreEqual(Small, queue.DesiredNumWorkers);
Assert.Equal(Small, queue.DesiredNumWorkers);
// Tasks don't go down immediately
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Large, queue._tasks.Count);
// After things re-poll, they should be cleaned
await Task.Delay(PollMS * 2);
Assert.AreEqual(Small, queue._tasks.Count);
Assert.Equal(Small, queue._tasks.Count);
}
}
[TestMethod]
[Fact]
public async Task DynamicNumThreads_IncreasedWhileWorking()
{
var subj = new BehaviorSubject<int>(Small);
var tcs = new TaskCompletionSource<bool>();
using (var queue = new WorkQueue(subj))
{
Assert.AreEqual(Small, queue.DesiredNumWorkers);
Assert.AreEqual(Small, queue._tasks.Count);
Assert.Equal(Small, queue.DesiredNumWorkers);
Assert.Equal(Small, queue._tasks.Count);
Enumerable.Range(0, Small).Do(_ => queue.QueueTask(() => tcs.Task));
subj.OnNext(Large);
Assert.AreEqual(Large, queue.DesiredNumWorkers);
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Large, queue.DesiredNumWorkers);
Assert.Equal(Large, queue._tasks.Count);
Task.Run(() => tcs.SetResult(true)).FireAndForget();
Assert.AreEqual(Large, queue.DesiredNumWorkers);
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Large, queue.DesiredNumWorkers);
Assert.Equal(Large, queue._tasks.Count);
await Task.Delay(PollMS * 2);
Assert.AreEqual(Large, queue.DesiredNumWorkers);
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Large, queue.DesiredNumWorkers);
Assert.Equal(Large, queue._tasks.Count);
}
}
[TestMethod]
[Fact]
public async Task DynamicNumThreads_DecreasedWhileWorking()
{
var subj = new BehaviorSubject<int>(Large);
var tcs = new TaskCompletionSource<bool>();
using (var queue = new WorkQueue(subj))
{
Assert.AreEqual(Large, queue.DesiredNumWorkers);
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Large, queue.DesiredNumWorkers);
Assert.Equal(Large, queue._tasks.Count);
Enumerable.Range(0, Large).Do(_ => queue.QueueTask(() => tcs.Task));
subj.OnNext(Small);
Assert.AreEqual(Small, queue.DesiredNumWorkers);
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Small, queue.DesiredNumWorkers);
Assert.Equal(Large, queue._tasks.Count);
// After things re-poll, they should still be working at max
await Task.Delay(PollMS * 2);
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Large, queue._tasks.Count);
// Complete, repoll, and check again
Task.Run(() => tcs.SetResult(true)).FireAndForget();
await Task.Delay(PollMS * 2);
Assert.AreEqual(Small, queue._tasks.Count);
Assert.Equal(Small, queue._tasks.Count);
}
}
[TestMethod]
[Fact]
public async Task DynamicNumThreads_IncreasedThenDecreased()
{
var subj = new BehaviorSubject<int>(Small);
using (var queue = new WorkQueue(subj))
{
Assert.AreEqual(Small, queue.DesiredNumWorkers);
Assert.AreEqual(Small, queue._tasks.Count);
Assert.Equal(Small, queue.DesiredNumWorkers);
Assert.Equal(Small, queue._tasks.Count);
subj.OnNext(Large);
Assert.AreEqual(Large, queue.DesiredNumWorkers);
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Large, queue.DesiredNumWorkers);
Assert.Equal(Large, queue._tasks.Count);
subj.OnNext(Small);
// Still large number of threads, as not immediate
Assert.AreEqual(Small, queue.DesiredNumWorkers);
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Small, queue.DesiredNumWorkers);
Assert.Equal(Large, queue._tasks.Count);
// After things re-poll, they should still be working at max
await Task.Delay(PollMS * 2);
Assert.AreEqual(Small, queue.DesiredNumWorkers);
Assert.AreEqual(Small, queue._tasks.Count);
Assert.Equal(Small, queue.DesiredNumWorkers);
Assert.Equal(Small, queue._tasks.Count);
}
}
[TestMethod]
[Fact]
public async Task DynamicNumThreads_DecreasedThenIncreased()
{
var subj = new BehaviorSubject<int>(Large);
using (var queue = new WorkQueue(subj))
{
Assert.AreEqual(Large, queue.DesiredNumWorkers);
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Large, queue.DesiredNumWorkers);
Assert.Equal(Large, queue._tasks.Count);
subj.OnNext(Small);
Assert.AreEqual(Small, queue.DesiredNumWorkers);
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Small, queue.DesiredNumWorkers);
Assert.Equal(Large, queue._tasks.Count);
subj.OnNext(Large);
// New threads allocated immediately
Assert.AreEqual(Large, queue.DesiredNumWorkers);
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Large, queue.DesiredNumWorkers);
Assert.Equal(Large, queue._tasks.Count);
// After things re-poll, still here
await Task.Delay(PollMS * 2);
Assert.AreEqual(Large, queue.DesiredNumWorkers);
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Large, queue.DesiredNumWorkers);
Assert.Equal(Large, queue._tasks.Count);
}
}
#endregion
@ -172,7 +168,7 @@ namespace Wabbajack.Test
/// The solution to this is just make sure that any work done relating to WorkQueue be done within its own Task.Run() call, so that if it that thread
/// "takes over" a workqueue loop, it doesn't matter as it was a threadpool thread anyway.
/// </summary>
[TestMethod]
[Fact]
public async Task Deadlock()
{
var task = Task.Run(async () =>
@ -186,8 +182,8 @@ namespace Wabbajack.Test
tcs.SetResult(true);
}
});
var completed = Task.WhenAny(Task.Delay(3000), task);
Assert.ReferenceEquals(completed, task);
var completed = await Task.WhenAny(Task.Delay(3000), task);
Assert.Equal(completed, task);
}
#endregion
@ -218,8 +214,8 @@ namespace Wabbajack.Test
object lockObj = new object();
using (var queue = new WorkQueue(subj))
{
Assert.AreEqual(Large, queue.DesiredNumWorkers);
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Large, queue.DesiredNumWorkers);
Assert.Equal(Large, queue._tasks.Count);
bool[] workStartedArray = new bool[Large];
async Task Job(int num, bool[] b)
@ -240,7 +236,7 @@ namespace Wabbajack.Test
// Show that all jobs are started
lock (lockObj)
{
Assert.AreEqual(Large, workStartedArray.Where(i => i).Count());
Assert.Equal(Large, workStartedArray.Where(i => i).Count());
}
await Task.Delay(15000);
@ -251,8 +247,8 @@ namespace Wabbajack.Test
// that kicked it off and is in charge of the continuation tasks.
// Parallel worker Tasks have now coalesced into a single thread
Task.Run(() => tcs.SetResult(true)).FireAndForget();
Assert.AreEqual(Large, queue.DesiredNumWorkers);
Assert.AreEqual(Large, queue._tasks.Count);
Assert.Equal(Large, queue.DesiredNumWorkers);
Assert.Equal(Large, queue._tasks.Count);
await Task.Delay(10000);
@ -264,7 +260,7 @@ namespace Wabbajack.Test
// Show that only one job was started/worked on (by our one coalesced worker thread)
lock (lockObj)
{
Assert.AreEqual(1, secondWorkStartedArray.Where(i => i).Count());
Assert.Equal(1, secondWorkStartedArray.Where(i => i).Count());
}
}
}

View File

@ -16,7 +16,7 @@ namespace Wabbajack.Common
{
public class WorkQueue : IDisposable
{
internal AsyncBlockingCollection<Func<Task>> Queue = new AsyncBlockingCollection<Func<Task>>();
internal BlockingCollection<Func<Task>> Queue = new BlockingCollection<Func<Task>>(new ConcurrentStack<Func<Task>>());
public const int UnassignedCpuId = 0;
@ -31,7 +31,8 @@ namespace Wabbajack.Common
public IObservable<CPUStatus> Status => _Status;
private int _nextCpuID = 1; // Start at 1, as 0 is "Unassigned"
internal Dictionary<int, Task> _tasks = new Dictionary<int, Task>();
// Public for testing reasons
public Dictionary<int, Task> _tasks = new Dictionary<int, Task>();
public int DesiredNumWorkers { get; private set; } = 0;
private CancellationTokenSource _shutdown = new CancellationTokenSource();
@ -50,7 +51,7 @@ namespace Wabbajack.Common
private readonly Subject<IObservable<int>> _activeNumThreadsObservable = new Subject<IObservable<int>>();
public TimeSpan PollMS = TimeSpan.FromMilliseconds(200);
public const int PollMS = 200;
/// <summary>
/// Creates a WorkQueue with the given number of threads
@ -124,7 +125,7 @@ namespace Wabbajack.Common
bool got;
try
{
(got, f) = await Queue.TryTake(PollMS, _shutdown.Token);
got = Queue.TryTake(out f, PollMS, _shutdown.Token);
}
catch (Exception)
{

View File

@ -4,7 +4,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using Wabbajack.Common;
using Wabbajack.Lib;
using Wabbajack.Lib.LibCefHelpers;
using Wabbajack.Util;
namespace Wabbajack.Test
{

View File

@ -1,31 +0,0 @@
using Alphaleonis.Win32.Filesystem;
using Wabbajack.Common;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Utils = Wabbajack.Common.Utils;
namespace Wabbajack.Test
{
[TestClass]
public class MiscTests
{
[TestMethod]
public void TestDiskSpeed()
{
using (var queue = new WorkQueue())
{
var speed = Utils.TestDiskSpeed(queue, @".\");
}
}
[TestMethod]
public void TestHash()
{
const string data = "Cheese for Everyone!";
File.WriteAllText("test.data", data);
Assert.AreEqual("eSIyd+KOG3s=", "test.data".FileHashCached(), "Hash is cached");
Assert.IsTrue(Utils.TryGetHashCache("test.data", out var fileHash), "New caching method is invoked");
Assert.AreEqual("eSIyd+KOG3s=", fileHash, "The correct hash value is cached");
Assert.AreNotEqual("eSIyd+KOG3s=", File.ReadAllText("test.data" + Consts.HashFileExtension), "We don't store the hash in plaintext");
}
}
}

View File

@ -1,230 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Wabbajack.Common;
namespace Wabbajack.Test
{
[TestClass]
public class PMapTests
{
const int TypicalThreadCount = 6;
const int TypicalDelayMS = 50;
const int TimeoutSeconds = 15;
[TestMethod]
public async Task Typical_Action()
{
using (var queue = new WorkQueue(TypicalThreadCount))
{
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var output = new List<int>();
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
.PMap(queue, (item) =>
{
Assert.IsTrue(WorkQueue.WorkerThread);
Thread.Sleep(TypicalDelayMS);
lock (output)
{
output.Add(item);
}
});
await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.IsTrue(input.SequenceEqual(output.OrderBy(i => i)));
}
}
[TestMethod]
public async Task Typical_Func()
{
using (var queue = new WorkQueue(TypicalThreadCount))
{
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
.PMap(queue, (item) =>
{
Assert.IsTrue(WorkQueue.WorkerThread);
Thread.Sleep(TypicalDelayMS);
return item.ToString();
});
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.IsTrue(input.Select(i => i.ToString()).SequenceEqual(results));
}
}
[TestMethod]
public async Task Typical_Task()
{
using (var queue = new WorkQueue(TypicalThreadCount))
{
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var output = new List<int>();
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
.PMap(queue, async (item) =>
{
Assert.IsTrue(WorkQueue.WorkerThread);
await Task.Delay(TypicalDelayMS);
lock (output)
{
output.Add(item);
}
});
await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.IsTrue(input.SequenceEqual(output.OrderBy(i => i)));
}
}
[TestMethod]
public async Task Typical_TaskReturn()
{
using (var queue = new WorkQueue(TypicalThreadCount))
{
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
.PMap(queue, async (item) =>
{
Assert.IsTrue(WorkQueue.WorkerThread);
await Task.Delay(TypicalDelayMS);
return item.ToString();
});
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.IsTrue(input.Select(i => i.ToString()).SequenceEqual(results));
}
}
[TestMethod]
public async Task NestedAction()
{
using (var queue = new WorkQueue(TypicalThreadCount))
{
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
var output = new List<int>();
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
.PMap(queue, async (item) =>
{
Assert.IsTrue(WorkQueue.WorkerThread);
await Enumerable.Range(item * 100, TypicalThreadCount * 2)
.PMap(queue, async (subItem) =>
{
Assert.IsTrue(WorkQueue.WorkerThread);
Thread.Sleep(TypicalDelayMS);
lock (output)
{
output.Add(subItem);
}
});
});
await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.IsTrue(inputConstructedResults.SequenceEqual(output.OrderBy(i => i)));
}
}
[TestMethod]
public async Task Nested_Func()
{
using (var queue = new WorkQueue(TypicalThreadCount))
{
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
.PMap(queue, async (item) =>
{
Assert.IsTrue(WorkQueue.WorkerThread);
return await Enumerable.Range(item * 100, TypicalThreadCount * 2)
.PMap(queue, (subItem) =>
{
Assert.IsTrue(WorkQueue.WorkerThread);
Thread.Sleep(TypicalDelayMS);
return subItem;
});
});
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.IsTrue(inputConstructedResults.SequenceEqual(results.SelectMany(i => i)));
}
}
[TestMethod]
public async Task Nested_Task()
{
using (var queue = new WorkQueue(TypicalThreadCount))
{
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
var output = new List<int>();
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
.PMap(queue, async (item) =>
{
Assert.IsTrue(WorkQueue.WorkerThread);
await Enumerable.Range(item * 100, TypicalThreadCount * 2)
.PMap(queue, async (subItem) =>
{
Assert.IsTrue(WorkQueue.WorkerThread);
await Task.Delay(TypicalDelayMS);
lock (output)
{
output.Add(subItem);
}
});
});
await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.IsTrue(inputConstructedResults.SequenceEqual(output.OrderBy(i => i)));
}
}
[TestMethod]
public async Task Nested_TaskReturn()
{
using (var queue = new WorkQueue(TypicalThreadCount))
{
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
.PMap(queue, async (item) =>
{
Assert.IsTrue(WorkQueue.WorkerThread);
return await Enumerable.Range(item * 100, TypicalThreadCount * 2)
.PMap(queue, async (subItem) =>
{
Assert.IsTrue(WorkQueue.WorkerThread);
await Task.Delay(TypicalDelayMS);
return subItem;
});
});
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.IsTrue(inputConstructedResults.SequenceEqual(results.SelectMany(i => i)));
}
}
[TestMethod]
public async Task Nested_BackgroundThreadsInvolved()
{
using (var queue = new WorkQueue(TypicalThreadCount))
{
var input = Enumerable.Range(0, TypicalThreadCount * 2).ToArray();
var inputConstructedResults = input.SelectMany(i => Enumerable.Range(i * 100, TypicalThreadCount * 2));
var workTask = Enumerable.Range(0, TypicalThreadCount * 2)
.PMap(queue, async (item) =>
{
Assert.IsTrue(WorkQueue.WorkerThread);
return await Enumerable.Range(item * 100, TypicalThreadCount * 2)
.PMap(queue, async (subItem) =>
{
return await Task.Run(async () =>
{
Assert.IsTrue(WorkQueue.WorkerThread);
await Task.Delay(TypicalDelayMS);
return subItem;
});
});
});
var results = await workTask.TimeoutButContinue(TimeSpan.FromSeconds(TimeoutSeconds), () => throw new TimeoutException());
Assert.IsTrue(inputConstructedResults.SequenceEqual(results.SelectMany(i => i)));
}
}
}
}

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;
using Alphaleonis.Win32.Filesystem;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Wabbajack.Common;
@ -22,37 +23,37 @@ namespace Wabbajack.Test
WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), "tmp_data");
}
public string WorkingDirectory { get;}
public AbsolutePath WorkingDirectory { get;}
public string ID { get; }
public Random RNG => _rng;
public Game Game { get; set; }
public string TestFolder => Path.Combine(WorkingDirectory, ID);
public string GameFolder => Path.Combine(WorkingDirectory, ID, "game_folder");
public AbsolutePath TestFolder => WorkingDirectory.Combine(ID);
public AbsolutePath GameFolder => WorkingDirectory.Combine(ID, "game_folder");
public string MO2Folder => Path.Combine(WorkingDirectory, ID, "mo2_folder");
public string ModsFolder => Path.Combine(MO2Folder, Consts.MO2ModFolderName);
public string DownloadsFolder => Path.Combine(MO2Folder, "downloads");
public AbsolutePath MO2Folder => WorkingDirectory.Combine(ID, "mo2_folder");
public AbsolutePath ModsFolder => MO2Folder.Combine(Consts.MO2ModFolderName);
public AbsolutePath DownloadsFolder => MO2Folder.Combine("downloads");
public string InstallFolder => Path.Combine(TestFolder, "installed");
public AbsolutePath InstallFolder => TestFolder.Combine("installed");
public HashSet<string> Profiles = new HashSet<string>();
public List<string> Mods = new List<string>();
public void Configure()
public async Task Configure()
{
File.WriteAllLines(Path.Combine(MO2Folder, "ModOrganizer.ini"), new []
await MO2Folder.Combine("ModOrganizer.ini").WriteAllLinesAsync(new []
{
"[General]",
$"gameName={Game.MetaData().MO2Name}",
$"gamePath={GameFolder.Replace("\\", "\\\\")}",
$"gamePath={((string)GameFolder).Replace("\\", "\\\\")}",
$"download_directory={DownloadsFolder}"
});
Directory.CreateDirectory(DownloadsFolder);
Directory.CreateDirectory(Path.Combine(GameFolder, "Data"));
DownloadsFolder.CreateDirectory();
GameFolder.Combine("Data").CreateDirectory();
Profiles.Do(profile =>
{
@ -260,9 +261,6 @@ namespace Wabbajack.Test
return full_path;
}
public static object RandomeOne(params object[] opts)
{
return opts[_rng.Next(0, opts.Length)];
}
}
}

View File

@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Platforms>x64</Platforms>
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Platforms>x64</Platforms>
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PlatformTarget>x64</PlatformTarget>
@ -26,7 +26,6 @@
<ProjectReference Include="..\Wabbajack.Common.CSP\Wabbajack.Common.CSP.csproj" />
<ProjectReference Include="..\Wabbajack.Common\Wabbajack.Common.csproj" />
<ProjectReference Include="..\Wabbajack.Lib\Wabbajack.Lib.csproj" />
<ProjectReference Include="..\Wabbajack\Wabbajack.csproj" />
</ItemGroup>
</Project>

View File

@ -8,9 +8,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.console" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.console" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
</ItemGroup>
<ItemGroup>

View File

@ -38,6 +38,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wabbajack.CLI", "Wabbajack.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wabbajack.Launcher", "Wabbajack.Launcher\Wabbajack.Launcher.csproj", "{D6856DBF-C959-4867-A8A8-343DA2D2715E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wabbajack.Common.Test", "Wabbajack.Common.Test\Wabbajack.Common.Test.csproj", "{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -76,12 +78,6 @@ Global
{5D6A2EAF-6604-4C51-8AE2-A746B4BC5E3E}.Release|Any CPU.ActiveCfg = Release|x64
{5D6A2EAF-6604-4C51-8AE2-A746B4BC5E3E}.Release|x64.ActiveCfg = Release|x64
{5D6A2EAF-6604-4C51-8AE2-A746B4BC5E3E}.Release|x64.Build.0 = Release|x64
{37E4D421-8FD3-4D57-8F3A-7A511D6ED5C5}.Debug|Any CPU.ActiveCfg = Debug|x64
{37E4D421-8FD3-4D57-8F3A-7A511D6ED5C5}.Debug|x64.ActiveCfg = Debug|x64
{37E4D421-8FD3-4D57-8F3A-7A511D6ED5C5}.Debug|x64.Build.0 = Debug|x64
{37E4D421-8FD3-4D57-8F3A-7A511D6ED5C5}.Release|Any CPU.ActiveCfg = Release|x64
{37E4D421-8FD3-4D57-8F3A-7A511D6ED5C5}.Release|x64.ActiveCfg = Release|x64
{37E4D421-8FD3-4D57-8F3A-7A511D6ED5C5}.Release|x64.Build.0 = Release|x64
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Debug|x64.ActiveCfg = Debug|Any CPU
@ -128,6 +124,14 @@ Global
{D6856DBF-C959-4867-A8A8-343DA2D2715E}.Release|Any CPU.Build.0 = Release|Any CPU
{D6856DBF-C959-4867-A8A8-343DA2D2715E}.Release|x64.ActiveCfg = Release|Any CPU
{D6856DBF-C959-4867-A8A8-343DA2D2715E}.Release|x64.Build.0 = Release|Any CPU
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|Any CPU.Build.0 = Release|Any CPU
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|x64.ActiveCfg = Release|Any CPU
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Release|x64.Build.0 = Release|Any CPU
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Debug|x64.ActiveCfg = Debug|x64
{BA8A3E49-60D2-4BA2-B285-CB09FFDB6D32}.Debug|x64.Build.0 = Debug|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE