#nullable enable using System; using System.Collections.Generic; using System.IO; using System.Linq; using NUnit.Framework; using ShrinkNetwork; namespace ShrinkNetwork.Editor.Tests { public sealed class ShrinkNetworkSemanticScannerTests { [Test] public void NamespaceCollisionIsRejectedInsteadOfSilentlyDroppingAContract() { var exception = Assert.Throws(() => ShrinkNetworkSemanticScanner.ScanTypesForTests( typeof(CollisionA.SharedMessage), typeof(CollisionB.SharedMessage))); StringAssert.Contains("SharedMessage", exception!.Message); StringAssert.Contains(typeof(CollisionA.SharedMessage).FullName, exception.Message); StringAssert.Contains(typeof(CollisionB.SharedMessage).FullName, exception.Message); } [Test] public void PartialMessageUsesTheCompiledTypeAndIncludesEveryPart() { var result = ShrinkNetworkSemanticScanner.ScanTypesForTests(typeof(PartialMessage)); CollectionAssert.AreEqual( new[] { "First", "Second" }, result.Messages.Single().Properties.Select(property => property.Name)); } [Test] public void ComplexGenericPropertyKeepsItsSemanticTypeShape() { var result = ShrinkNetworkSemanticScanner.ScanTypesForTests( typeof(ComplexGenericMessage), typeof(SemanticPayload)); var property = result.Messages.Single().Properties.Single(); Assert.AreEqual("Dictionary>", property.Type); Assert.AreEqual("Payloads", property.Name); Assert.AreEqual("SemanticPayload", result.DataTypes.Single().Name); } } public sealed class ShrinkDedicatedServerTemplateProtectionTests { private string _root = string.Empty; private string _templateRoot = string.Empty; private string _outputRoot = string.Empty; [SetUp] public void SetUp() { _root = Path.Combine(Path.GetTempPath(), "ShrinkNetworkGeneratorTests", Guid.NewGuid().ToString("N")); _templateRoot = Path.Combine(_root, "Template"); _outputRoot = Path.Combine(_root, "Output"); Directory.CreateDirectory(_templateRoot); } [TearDown] public void TearDown() { if (Directory.Exists(_root)) Directory.Delete(_root, true); } [Test] public void ModifiedManagedFileBlocksRegenerationBeforeAnyFileIsWritten() { File.WriteAllText(Path.Combine(_templateRoot, "README.md.txt"), "generated-v1"); File.WriteAllText(Path.Combine(_templateRoot, "settings.json.txt"), "settings-v1"); ShrinkDedicatedServerScaffoldGenerator.CopyTemplateProject(_templateRoot, _outputRoot); File.WriteAllText(Path.Combine(_outputRoot, "README.md"), "manual-change"); File.WriteAllText(Path.Combine(_templateRoot, "settings.json.txt"), "settings-v2"); Assert.Throws(() => ShrinkDedicatedServerScaffoldGenerator.CopyTemplateProject(_templateRoot, _outputRoot)); Assert.AreEqual("manual-change", File.ReadAllText(Path.Combine(_outputRoot, "README.md"))); Assert.AreEqual("settings-v1", File.ReadAllText(Path.Combine(_outputRoot, "settings.json"))); } [Test] public void UnmodifiedManagedFilesCanBeRegeneratedFromANewerTemplate() { File.WriteAllText(Path.Combine(_templateRoot, "README.md.txt"), "generated-v1"); ShrinkDedicatedServerScaffoldGenerator.CopyTemplateProject(_templateRoot, _outputRoot); File.WriteAllText(Path.Combine(_templateRoot, "README.md.txt"), "generated-v2"); ShrinkDedicatedServerScaffoldGenerator.CopyTemplateProject(_templateRoot, _outputRoot); Assert.AreEqual("generated-v2", File.ReadAllText(Path.Combine(_outputRoot, "README.md"))); } } [ShrinkNetworkMessage(9101, "tests/partial")] internal sealed partial class PartialMessage : IShrinkNetworkMessage { public int First { get; set; } } internal sealed partial class PartialMessage { public string Second { get; set; } = string.Empty; } [ShrinkNetworkMessage(9102, "tests/complex-generic")] internal sealed class ComplexGenericMessage : IShrinkNetworkMessage { public Dictionary> Payloads { get; set; } = new(); } internal sealed class SemanticPayload { public Guid Id { get; set; } } } namespace ShrinkNetwork.Editor.Tests.CollisionA { [ShrinkNetworkMessage(9110, "tests/collision-a")] internal sealed class SharedMessage : IShrinkNetworkMessage { } } namespace ShrinkNetwork.Editor.Tests.CollisionB { [ShrinkNetworkMessage(9111, "tests/collision-b")] internal sealed class SharedMessage : IShrinkNetworkMessage { } }