Tests: remove generators

This commit is contained in:
vis2k 2021-08-07 13:28:18 +08:00
parent 4facadfc24
commit 46d7e2d6a3
9 changed files with 696 additions and 1388 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,21 @@
// Generated by CollectionWriterGenerator.cs // Generated by CollectionWriterGenerator.cs
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Mirror.Tests.Generators;
using NUnit.Framework; using NUnit.Framework;
using UnityEngine; using UnityEngine;
namespace Mirror.Tests.Generated.CollectionWriters namespace Mirror.Tests.Generated.CollectionWriters
{ {
public struct FloatStringStruct
{
public float value;
public string anotherValue;
}
public class ClassWithNoConstructor
{
public int a;
}
public class Array_int_Test public class Array_int_Test
{ {

View File

@ -1,30 +0,0 @@
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace Mirror.Tests.Generators
{
public class GeneratorBase
{
protected const string BaseNameSpace = "Mirror.Tests.Generated";
protected static void Save(string main, string fileName, bool compile = true)
{
string filePath = compile
? $"Mirror/Tests/Editor/Generated/{fileName}.gen.cs"
: $"Mirror/Tests/Editor/Generated/.{fileName}.gen.cs";
File.WriteAllText($"{Application.dataPath}/{filePath}", main);
if (compile)
{
AssetDatabase.Refresh();
AssetDatabase.ImportAsset($"Assets/{filePath}");
}
}
protected static string Merge(IEnumerable<string> strs, string separator = "\n")
{
return string.Join(separator, strs);
}
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 656c161a6f1cee84a86e652dedec2b57
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: b54dfbdcf5ccb734aaab0c077c22ed6e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,350 +0,0 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace Mirror.Tests.Generators
{
public class AttributeTestGenerator : GeneratorBase
{
[MenuItem("Tools/Generate Test files/Attributes")]
public static void GenerateTestFiles()
{
List<string> classes = new List<string>();
foreach (string baseClass in baseClassArray)
{
List<string> functions = new List<string>();
List<string> tests = new List<string>();
foreach (string attribute in attributeArray)
{
foreach (string returnType in returnTypeArray)
{
functions.Add(AttributeFunction(attribute, returnType));
tests.Add(TestFunction(attribute, baseClass, returnType));
functions.Add(AttributeOutFunction(attribute, returnType));
tests.Add(TestOutFunction(attribute, baseClass, returnType));
}
}
classes.Add(Classes(baseClass, functions, tests));
}
string main = Main(classes);
Save(main, "AttritubeTest");
}
static string[] returnTypeArray = new string[]
{
"float",
"double",
"bool",
"char",
"byte",
"int",
"long",
"ulong",
nameof(Vector3),
nameof(ClassWithNoConstructor),
nameof(ClassWithConstructor),
};
static string ReturnTypeToFullName(string returnType)
{
switch (returnType)
{
case "float":
return typeof(float).FullName;
case "double":
return typeof(double).FullName;
case "bool":
return typeof(bool).FullName;
case "char":
return typeof(char).FullName;
case "byte":
return typeof(byte).FullName;
case "int":
return typeof(int).FullName;
case "long":
return typeof(long).FullName;
case "ulong":
return typeof(ulong).FullName;
case nameof(Vector3):
return typeof(Vector3).FullName;
case nameof(ClassWithNoConstructor):
return typeof(ClassWithNoConstructor).FullName;
case nameof(ClassWithConstructor):
return typeof(ClassWithConstructor).FullName;
default:
return returnType;
}
}
static string[] attributeArray = new string[]
{
"Client",
"Server",
"ClientCallback",
"ServerCallback"
};
static string[] baseClassArray = new string[]
{
"NetworkBehaviour",
"MonoBehaviour",
"ClassWithNoConstructor" // non unity class
};
const string NameSpace = BaseNameSpace + ".Attributes";
static string Main(IEnumerable<string> classes)
{
string mergedClasses = Merge(classes);
return $@"// Generated by {nameof(AttributeTestGenerator)}.cs
using Mirror.Tests.Generators;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace {NameSpace}
{{
{mergedClasses}
}}";
}
static string Classes(string baseClass, IEnumerable<string> functions, IEnumerable<string> tests)
{
string mergedFunctions = Merge(functions);
string mergedTests = Merge(tests);
string setupBody = SetupForBaseClass(baseClass);
string teardownBody = TearDownForBaseClass(baseClass);
return $@"
public class {AttributeBehaviourName(baseClass)} : {baseClass}
{{
public static readonly float Expected_float = 2020f;
public static readonly double Expected_double = 2.54;
public static readonly bool Expected_bool = true;
public static readonly char Expected_char = 'a';
public static readonly byte Expected_byte = 224;
public static readonly int Expected_int = 103;
public static readonly long Expected_long = -123456789L;
public static readonly ulong Expected_ulong = 123456789UL;
public static readonly Vector3 Expected_Vector3 = new Vector3(29, 1, 10);
public static readonly ClassWithNoConstructor Expected_ClassWithNoConstructor = new ClassWithNoConstructor {{ a = 10 }};
public static readonly ClassWithConstructor Expected_ClassWithConstructor = new ClassWithConstructor(29);
{mergedFunctions}
}}
public class AttributeTest_{baseClass}
{{
AttributeBehaviour_{baseClass} behaviour;
GameObject go;
[OneTimeSetUp]
public void SetUp()
{{
{setupBody}
}}
[OneTimeTearDown]
public void TearDown()
{{
{teardownBody}
NetworkClient.connectState = ConnectState.None;
NetworkServer.active = false;
}}
{mergedTests}
}}";
}
static string SetupForBaseClass(string baseClass)
{
switch (baseClass)
{
case "NetworkBehaviour":
case "MonoBehaviour":
return SetupBodyMonoBehaviour(baseClass);
default:
return SetupBodyClass(baseClass);
}
}
static string TearDownForBaseClass(string baseClass)
{
switch (baseClass)
{
case "NetworkBehaviour":
case "MonoBehaviour":
return TearDownBodyMonoBehaviour();
default:
return TearDownBodyClass();
}
}
static string SetupBodyMonoBehaviour(string baseClass)
{
return
$@"go = new GameObject();
behaviour = go.AddComponent<{AttributeBehaviourName(baseClass)}>();";
}
static string TearDownBodyMonoBehaviour()
{
return "UnityEngine.Object.DestroyImmediate(go);";
}
static string SetupBodyClass(string baseClass)
{
return $@"behaviour = new {AttributeBehaviourName(baseClass)}();";
}
static string TearDownBodyClass()
{
return "";
}
static string AttributeBehaviourName(string baseClass)
{
return $"AttributeBehaviour_{baseClass}";
}
static string AttributeFunctionName(string attribute, string returnType)
{
return $"{attribute}_{returnType}_Function";
}
static string AttributeOutFunctionName(string attribute, string returnType)
{
return $"{attribute}_{returnType}_out_Function";
}
static string AttributeFunction(string attribute, string returnType)
{
return $@"
[{attribute}]
public {returnType} {AttributeFunctionName(attribute, returnType)}()
{{
return Expected_{returnType};
}}";
}
static string TestFunction(string attribute, string baseClass, string returnType)
{
string activeLine = ActivateServerClient(attribute);
string logLine = attribute.Contains("Callback")
? ""
: ExpectedLog(attribute, baseClass, returnType);
return TestFunctionBody(attribute, baseClass, returnType, activeLine, logLine);
}
static string TestFunctionBody(string attribute, string baseClass, string returnType, string activeLine, string logLine)
{
return $@"
[Test]
[TestCase(true)]
[TestCase(false)]
public void {attribute}_{returnType}_returnsValue(bool active)
{{
{activeLine}
{returnType} expected = active ? {AttributeBehaviourName(baseClass)}.Expected_{returnType} : default;
{logLine}
{returnType} actual = behaviour.{AttributeFunctionName(attribute, returnType)}();
Assert.AreEqual(expected, actual);
}}";
}
static string ActivateServerClient(string attribute)
{
if (attribute.Contains("Server"))
{
return "NetworkServer.active = active;";
}
else if (attribute.Contains("Client"))
{
return "NetworkClient.connectState = active ? ConnectState.Connected : ConnectState.None;";
}
else
{
throw new System.ArgumentException("Attribute must include Server or Client");
}
}
static string ExpectedLog(string attribute, string baseClass, string returnType)
{
string functionFullName = $"{NameSpace}.{AttributeBehaviourName(baseClass)}::{AttributeFunctionName(attribute, returnType)}()";
string returnTypeFullName = ReturnTypeToFullName(returnType);
return $@"
if (!active)
{{
LogAssert.Expect(LogType.Warning, ""[{attribute}] function '{returnTypeFullName} {functionFullName}' called when {attribute.ToLower()} was not active"");
}}";
}
static string AttributeOutFunction(string attribute, string returnType)
{
return $@"
[{attribute}]
public void {AttributeOutFunctionName(attribute, returnType)}(out {returnType} value)
{{
value = Expected_{returnType};
}}";
}
static string TestOutFunction(string attribute, string baseClass, string returnType)
{
string activeLine = ActivateServerClient(attribute);
string logLine = attribute.Contains("Callback")
? ""
: ExpectedOutLog(attribute, baseClass, returnType);
return TestOutFunctionBody(attribute, baseClass, returnType, activeLine, logLine);
}
static string TestOutFunctionBody(string attribute, string baseClass, string returnType, string activeLine, string logLine)
{
return $@"
[Test]
[TestCase(true)]
[TestCase(false)]
public void {attribute}_{returnType}_setsOutValue(bool active)
{{
{activeLine}
{returnType} expected = active ? {AttributeBehaviourName(baseClass)}.Expected_{returnType} : default;
{logLine}
behaviour.{AttributeOutFunctionName(attribute, returnType)}(out {returnType} actual);
Assert.AreEqual(expected, actual);
}}";
}
static string ExpectedOutLog(string attribute, string baseClass, string returnType)
{
string returnTypeFullName = ReturnTypeToFullName(returnType);
string functionFullName = $"{NameSpace}.{AttributeBehaviourName(baseClass)}::{AttributeOutFunctionName(attribute, returnType)}({returnTypeFullName}&)";
return $@"
if (!active)
{{
LogAssert.Expect(LogType.Warning, ""[{attribute}] function 'System.Void {functionFullName}' called when {attribute.ToLower()} was not active"");
}}";
}
}
public class ClassWithNoConstructor
{
public int a;
}
public class ClassWithConstructor
{
public int a;
public ClassWithConstructor(int a)
{
this.a = a;
}
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 104f059dd2dec5942aa8d12cc1e4d81f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,293 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace Mirror.Tests.Generators
{
public struct FloatStringStruct
{
public float value;
public string anotherValue;
}
public class CollectionWriterGenerator : GeneratorBase
{
[MenuItem("Tools/Generate Test files/Collection Writer")]
public static void GenerateTestFiles()
{
List<string> classes = new List<string>();
foreach (string collectionType in collectionTypes)
{
foreach (string elementType in elementTypes)
{
IEnumerable<string> dataValues = valuesForType(elementType);
classes.Add(Classes(elementType, collectionType, dataValues));
}
}
string main = Main(classes);
Save(main, "CollectionWriterTests", true);
}
static readonly string[] elementTypes = new string[]
{
"int",
"string",
nameof(Vector3),
nameof(FloatStringStruct),
nameof(ClassWithNoConstructor)
};
static IEnumerable<string> valuesForType(string elementType)
{
switch (elementType)
{
case "int":
return new string[] { "3", "4", "5" };
case "string":
return new string[] { "\"Some\"", "\"String\"", "\"Value\"" };
case nameof(Vector3):
return new string[] {
"new Vector3(1, 2, 3)",
"new Vector3(4, 5, 6)",
"new Vector3(7, 8, 9)"
};
case nameof(FloatStringStruct):
return new string[] {
"new FloatStringStruct { value = 3, anotherValue = \"Some\" }",
"new FloatStringStruct { value = 4, anotherValue = \"String\" }",
"new FloatStringStruct { value = 5, anotherValue = \"Values\" }",
};
case nameof(ClassWithNoConstructor):
return new string[] {
"new ClassWithNoConstructor { a = 3 }",
"new ClassWithNoConstructor { a = 4 }",
"new ClassWithNoConstructor { a = 5 }",
};
default:
throw new System.ArgumentException($"No Values for {elementType}");
}
}
const string ArrayType = "Array";
const string ListType = "List";
const string ArraySegmentType = "ArraySegment";
static readonly string[] collectionTypes = new string[]
{
ArrayType,
ArraySegmentType,
ListType,
};
const string NameSpace = BaseNameSpace + ".CollectionWriters";
static string Main(IEnumerable<string> classes)
{
string mergedClasses = Merge(classes);
return $@"// Generated by {nameof(CollectionWriterGenerator)}.cs
using System;
using System.Collections.Generic;
using Mirror.Tests.Generators;
using NUnit.Framework;
using UnityEngine;
namespace {NameSpace}
{{
{mergedClasses}
}}";
}
static string MessageField(string elementType, string collectionType)
{
switch (collectionType)
{
case ArrayType:
return $"{elementType}[]";
case ListType:
return $"List<{elementType}>";
case ArraySegmentType:
return $"ArraySegment<{elementType}>";
default:
throw new System.ArgumentException($"Collection must be array, list or segment but was {collectionType}");
}
}
static string Classes(string elementType, string collectionType, IEnumerable<string> dataValues)
{
string messageField = MessageField(elementType, collectionType);
string[] values = dataValues.ToArray();
return $@"
public class {collectionType}_{elementType}_Test
{{
public class Message : NetworkMessage
{{
public {messageField} collection;
}}
[Test]
public void SendsNull()
{{
Message message = new Message
{{
collection = default
}};
byte[] data = MessagePacker.Pack(message);
Message unpacked = MessagePacker.Unpack<Message>(data);
{messageField} unpackedCollection = unpacked.collection;
Assert.That({CheckCollection(collectionType)}, Is.Null.Or.Empty);
}}
[Test]
public void SendsEmpty()
{{
{NewEmptyCollection(elementType, collectionType)}
byte[] data = MessagePacker.Pack(message);
Message unpacked = MessagePacker.Unpack<Message>(data);
{messageField} unpackedCollection = unpacked.collection;
Assert.IsNotNull({CheckCollection(collectionType)});
Assert.IsEmpty({CheckCollection(collectionType)});
}}
[Test]
public void SendsData()
{{
{NewCollection(elementType, collectionType, dataValues)}
byte[] data = MessagePacker.Pack(message);
Message unpacked = MessagePacker.Unpack<Message>(data);
{messageField} unpackedCollection = unpacked.collection;
Assert.IsNotNull({CheckCollection(collectionType)});
Assert.IsNotEmpty({CheckCollection(collectionType)});
Assert.That({ElementEqualCheck(elementType, ReadValue(collectionType, 0), values[0])});
Assert.That({ElementEqualCheck(elementType, ReadValue(collectionType, 1), values[1])});
Assert.That({ElementEqualCheck(elementType, ReadValue(collectionType, 2), values[2])});
}}
}}";
}
static string ElementEqualCheck(string elementType, string collectionValue, string expected)
{
switch (elementType)
{
case nameof(ClassWithNoConstructor):
return $"{collectionValue}.a, Is.EqualTo({expected}.a)";
default:
return $"{collectionValue}, Is.EqualTo({expected})";
}
}
static string CheckCollection(string collectionType)
{
switch (collectionType)
{
case ArraySegmentType:
return $"unpackedCollection.Array";
default:
return $"unpackedCollection";
}
}
static string ReadValue(string collectionType, int index)
{
switch (collectionType)
{
case ArraySegmentType:
return $"unpackedCollection.Array[unpackedCollection.Offset + {index}]";
default:
return $"unpackedCollection[{index}]";
}
}
static string NewEmptyCollection(string elementType, string collectionType)
{
switch (collectionType)
{
case ArraySegmentType:
return NewEmptyArragSegment(elementType, collectionType);
default:
return NewEmptyCollectionDefault(elementType, collectionType);
}
}
static string NewEmptyCollectionDefault(string elementType, string collectionType)
{
string messageField = MessageField(elementType, collectionType);
return $@"Message = new Message
{{
collection = new {messageField} {{}}
}};";
}
static string NewEmptyArragSegment(string elementType, string collectionType)
{
string messageField = MessageField(elementType, collectionType);
return $@"{elementType}[] array = new {elementType}[]
{{
default,
default,
default,
}};
Message message = new Message
{{
collection = new {messageField}(array, 0, 0)
}};";
}
static string NewCollection(string elementType, string collectionType, IEnumerable<string> dataValues)
{
switch (collectionType)
{
case ArraySegmentType:
return NewArragSegment(elementType, collectionType, dataValues);
default:
return NewCollectionDefault(elementType, collectionType, dataValues);
}
}
static string NewCollectionDefault(string elementType, string collectionType, IEnumerable<string> dataValues)
{
string mergedValues = Merge(dataValues, ", ");
string messageField = MessageField(elementType, collectionType);
return $@"Message = new Message
{{
collection = new {messageField}
{{
{mergedValues}
}}
}};";
}
static string NewArragSegment(string elementType, string collectionType, IEnumerable<string> dataValues)
{
return $@"{elementType}[] array = new {elementType}[]
{{
default,
{Merge(dataValues, ", ")},
default,
default,
default,
}};
Message message = new Message
{{
collection = new ArraySegment<{elementType}>(array, 1, 3)
}};";
}
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 3c0d546467b3e40fdb2b81af752a29b6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: