internal static bool AreEqual(ITestOutputHelper testOutputHelper, Type sourceType, Type targetType, CastResult compilerResult, CastResult castResult, CastFlag expectedCastFlag) { if (compilerResult.IsSuccessful == true && castResult.IsSuccessful == false) { // Let's assert the details if the compiler generates a successful result // but the CastTo method does not the same. var castFlagsAreEqual = compilerResult.CastFlag == castResult.CastFlag || castResult.CastFlag == CastFlag.Implicit; if (!castFlagsAreEqual) { testOutputHelper.WriteLine("CastFlags of conversion between {0} and {1} are not equal." + Environment.NewLine + "Expected CastFlag: {2}" + Environment.NewLine + "Resulted CastFlag: {3}" + Environment.NewLine, sourceType.GetFormattedName(), targetType.GetFormattedName(), expectedCastFlag, castResult.CastFlag); return false; } var valuesAreNotEqual = compilerResult.CastFlag == castResult.CastFlag && !Equals(compilerResult.Value, castResult.Value); if (valuesAreNotEqual) { testOutputHelper.WriteLine("Result of {0} conversion between {1} and {2} are not equal.", expectedCastFlag == CastFlag.Implicit ? "implicit" : "explicit", sourceType.GetFormattedName(), targetType.GetFormattedName()); return false; } } return true; }
public CompilerConversionTestCase(Type sourceType, Type targetType, CastFlag castFlag, string codeline = null, CompilerError compilerError = null) { this.SourceType = sourceType; this.TargetType = targetType; this.Codeline = codeline; this.CompilerError = compilerError; this.CastFlag = castFlag; }
internal static CastResult CastValueWithGeneratedCode(object value, Type sourceType, Type targetType, CastFlag castFlag) { string className = "GeneratedTestClass"; string methodName = "RunTest"; string castLine = string.Format( "{0} x = {1}value; return x;", targetType.GetFormattedFullname(), castFlag == CastFlag.Implicit ? string.Empty : "(" + targetType.GetFormattedFullname() + ")"); string code = "public class " + className + " { public " + targetType.GetFormattedFullname() + " " + methodName + "(" + sourceType.GetFormattedFullname() + " value)" + "{" + castLine + "}}"; using (CSharpCodeProvider provider = new CSharpCodeProvider()) { var compilerParams = new CompilerParameters(); compilerParams.ReferencedAssemblies.Add(typeof(CastTestRunner).Assembly.Location); compilerParams.GenerateExecutable = false; compilerParams.GenerateInMemory = true; var compilationResult = provider.CompileAssemblyFromSource(compilerParams, code); if (compilationResult.Errors.HasErrors) { var compilerException = new AggregateException("CastValueWithGeneratedCode failed to generate test class.", compilationResult.Errors .OfType<CompilerError>() .Where(e => !e.IsWarning) .Select(e => new CompilerException(e.Line, e.Column, e.ErrorText))); return new CastResult(compilerException, castFlag); } var generatedClass = compilationResult.CompiledAssembly.GetType(className); var instance = Activator.CreateInstance(generatedClass); var testMethod = generatedClass.GetMethod(methodName); try { var castedValue = testMethod.Invoke(instance, new[] { value }); return new CastResult(castedValue, castFlag); } catch (TargetInvocationException ex) { if (ex.InnerException is InvalidProgramException) { // This is most probably an error in Roslyn compiler. // See http://stackoverflow.com/questions/18342943/serious-bugs-with-lifted-nullable-conversions-from-int-allowing-conversion-from return new CastResult(value, castFlag); } return new CastResult(ex, castFlag); } catch (Exception ex) { return new CastResult(ex, castFlag); } } }
public CastResult(Exception exception, CastFlag castFlag) : base(exception) { this.CastFlag = castFlag; }
public CastResult(object value, CastFlag castFlag) : base(value) { this.CastFlag = castFlag; }
private static string GetCodeline(int index, Type sourceType, Type targetType, CastFlag castFlag) { return string.Format( "{0} var{1} = {2}Get<{3}>();", targetType.GetFormattedFullname(), index, castFlag == CastFlag.Implicit ? string.Empty : "(" + targetType.GetFormattedFullname() + ")", sourceType.GetFormattedFullname()); }
private static List<CompilerConversionTestCase> GenerateTestCases(IEnumerable<Type> allTypes, CastFlag castFlag) { // generate cross product of given types var typeCrossProduct = allTypes.SelectMany(type => allTypes, (sourceType, targetType) => new { sourceType, targetType }) .Select((type, index) => new { type.sourceType, type.targetType, index, codeline = GetCodeline(index, type.sourceType, type.targetType, castFlag) }).ToArray(); // create the code to pass to the compiler var code = string.Join( Environment.NewLine, new[] { "namespace A { public class B { static T Get<T>() { return default(T); } public void C() {" }.Concat( typeCrossProduct.Select(t => t.codeline)) .Concat(new[] { "}}}" })); // compile the code var provider = new CSharpCodeProvider(); var compilerParams = new CompilerParameters(); compilerParams.ReferencedAssemblies.Add(typeof(CastTestRunner).Assembly.Location); // reference the current assembly! compilerParams.GenerateExecutable = false; compilerParams.GenerateInMemory = true; var compilationResult = provider.CompileAssemblyFromSource(compilerParams, code); // determine the outcome of each conversion by matching compiler errors with conversions by line # var testCases = typeCrossProduct.GroupJoin(compilationResult.Errors.Cast<CompilerError>(), type => type.index, e => e.Line - 2, (type, errors) => new CompilerConversionTestCase(type.sourceType, type.targetType, castFlag, type.codeline, errors.FirstOrDefault())) .ToList(); // add a special case // this can't be verified by the normal means, since it's a private class ////testCases.Add(new CompilerConversionTestCase(typeof(PrivateOperators), typeof(int), string.Empty, default(CompilerError))); return testCases; }
public static void ReadSpellCastData(Packet packet, params object[] idx) { bool isSpellGo = packet.Opcode == Opcodes.GetOpcode(Opcode.SMSG_SPELL_GO, Direction.ServerToClient); WowGuid targetGUID = new WowGuid64(); var casterGUID = packet.ReadPackedGuid("CasterGUID", idx); packet.ReadPackedGuid("CasterUnit", idx); packet.ReadByte("CastID", idx); var spellId = packet.ReadInt32 <SpellId>("SpellID", idx); CastFlag flags = packet.ReadInt32E <CastFlag>("CastFlags", idx); packet.ReadUInt32("CastFlagsEx", idx); packet.ReadUInt32("CastTime", idx); if (isSpellGo) { var hitTargetsCount = packet.ReadByte("HitTargetsCount", idx); for (var i = 0; i < hitTargetsCount; ++i) { packet.ReadGuid("HitTarget", idx, i); } var missCount = packet.ReadByte("MissStatusCount", idx); for (var i = 0; i < missCount; ++i) { ReadSpellMissStatus(packet, idx, "MissStatus", i); } } TargetFlag targetFlags = TargetFlag.Self; ReadSpellTargetData(packet, ref targetFlags, targetGUID, idx, "Target"); if (flags.HasAnyFlag(CastFlag.PredictedPower)) { packet.ReadUInt32("RemainingPower"); } if (flags.HasAnyFlag(CastFlag.RuneInfo)) { ReadRuneData(packet, idx, "RemainingRunes"); } if (isSpellGo) { if (flags.HasAnyFlag(CastFlag.AdjustMissile)) { ReadMissileTrajectoryResult(packet, idx, "MissileTrajectory"); } } if (flags.HasAnyFlag(CastFlag.Projectile)) { ReadSpellAmmo(packet, idx, "Ammo"); } if (isSpellGo) { if (flags.HasAnyFlag(CastFlag.VisualChain)) { ReadProjectileVisual(packet, idx, "ProjectileVisual"); } if (targetFlags.HasAnyFlag(TargetFlag.DestinationLocation)) { packet.ReadByte("DestLocSpellCastIndex", idx); } if (targetFlags.HasAnyFlag(TargetFlag.ExtraTargets)) { var targetPointsCount = packet.ReadInt32("TargetPointsCount", idx); for (var i = 0; i < targetPointsCount; ++i) { ReadTargetLocation(packet, idx, "TargetPoints", i); } } } else { if (flags.HasAnyFlag(CastFlag.Immunity)) { ReadCreatureImmunities(packet, idx, "Immunities"); } if (flags.HasAnyFlag(CastFlag.HealPrediction)) { ReadSpellHealPrediction(packet, idx, "Predict"); } } if (flags.HasAnyFlag(CastFlag.Unknown21) && !isSpellGo) { NpcSpellClick spellClick = new NpcSpellClick { SpellID = (uint)spellId, CasterGUID = casterGUID, TargetGUID = targetGUID }; Storage.SpellClicks.Add(spellClick, packet.TimeSpan); } if (isSpellGo) { packet.AddSniffData(StoreNameType.Spell, spellId, "SPELL_GO"); } }
private static List <CompilerConversionTestCase> GenerateTestCases(IEnumerable <Type> allTypes, CastFlag castFlag) { // generate cross product of given types var typeCrossProduct = allTypes.SelectMany(type => allTypes, (sourceType, targetType) => new { sourceType, targetType }) .Select((type, index) => new { type.sourceType, type.targetType, index, codeline = GetCodeline(index, type.sourceType, type.targetType, castFlag) }).ToArray(); // create the code to pass to the compiler var code = string.Join( Environment.NewLine, new[] { "namespace A { public class B { static T Get<T>() { return default(T); } public void C() {" }.Concat( typeCrossProduct.Select(t => t.codeline)) .Concat(new[] { "}}}" })); // compile the code var provider = new CSharpCodeProvider(); var compilerParams = new CompilerParameters(); compilerParams.ReferencedAssemblies.Add(typeof(CastTestRunner).Assembly.Location); // reference the current assembly! compilerParams.GenerateExecutable = false; compilerParams.GenerateInMemory = true; var compilationResult = provider.CompileAssemblyFromSource(compilerParams, code); // determine the outcome of each conversion by matching compiler errors with conversions by line # var testCases = typeCrossProduct.GroupJoin(compilationResult.Errors.Cast <CompilerError>(), type => type.index, e => e.Line - 2, (type, errors) => new CompilerConversionTestCase(type.sourceType, type.targetType, castFlag, type.codeline, errors.FirstOrDefault())) .ToList(); // add a special case // this can't be verified by the normal means, since it's a private class ////testCases.Add(new CompilerConversionTestCase(typeof(PrivateOperators), typeof(int), string.Empty, default(CompilerError))); return(testCases); }
internal static bool AreEqual(ITestOutputHelper testOutputHelper, Type sourceType, Type targetType, CastResult compilerResult, CastResult castResult, CastFlag expectedCastFlag) { if (compilerResult.IsSuccessful == true && castResult.IsSuccessful == false) { // Let's assert the details if the compiler generates a successful result // but the CastTo method does not the same. var castFlagsAreEqual = compilerResult.CastFlag == castResult.CastFlag || castResult.CastFlag == CastFlag.Implicit; if (!castFlagsAreEqual) { testOutputHelper.WriteLine("CastFlags of conversion between {0} and {1} are not equal." + Environment.NewLine + "Expected CastFlag: {2}" + Environment.NewLine + "Resulted CastFlag: {3}" + Environment.NewLine, sourceType.GetFormattedName(), targetType.GetFormattedName(), expectedCastFlag, castResult.CastFlag); return(false); } var valuesAreNotEqual = compilerResult.CastFlag == castResult.CastFlag && !Equals(compilerResult.Value, castResult.Value); if (valuesAreNotEqual) { testOutputHelper.WriteLine("Result of {0} conversion between {1} and {2} are not equal.", expectedCastFlag == CastFlag.Implicit ? "implicit" : "explicit", sourceType.GetFormattedName(), targetType.GetFormattedName()); return(false); } } return(true); }
internal static CastResult CastValueWithGeneratedCode(object value, Type sourceType, Type targetType, CastFlag castFlag) { string className = "GeneratedTestClass"; string methodName = "RunTest"; string castLine = string.Format( "{0} x = {1}value; return x;", targetType.GetFormattedFullname(), castFlag == CastFlag.Implicit ? string.Empty : "(" + targetType.GetFormattedFullname() + ")"); string code = "public class " + className + " { public " + targetType.GetFormattedFullname() + " " + methodName + "(" + sourceType.GetFormattedFullname() + " value)" + "{" + castLine + "}}"; using (CSharpCodeProvider provider = new CSharpCodeProvider()) { var compilerParams = new CompilerParameters(); compilerParams.ReferencedAssemblies.Add(typeof(CastTestRunner).Assembly.Location); compilerParams.GenerateExecutable = false; compilerParams.GenerateInMemory = true; var compilationResult = provider.CompileAssemblyFromSource(compilerParams, code); if (compilationResult.Errors.HasErrors) { var compilerException = new AggregateException("CastValueWithGeneratedCode failed to generate test class.", compilationResult.Errors .OfType <CompilerError>() .Where(e => !e.IsWarning) .Select(e => new CompilerException(e.Line, e.Column, e.ErrorText))); return(new CastResult(compilerException, castFlag)); } var generatedClass = compilationResult.CompiledAssembly.GetType(className); var instance = Activator.CreateInstance(generatedClass); var testMethod = generatedClass.GetMethod(methodName); try { var castedValue = testMethod.Invoke(instance, new[] { value }); return(new CastResult(castedValue, castFlag)); } catch (TargetInvocationException ex) { if (ex.InnerException is InvalidProgramException) { // This is most probably an error in Roslyn compiler. // See http://stackoverflow.com/questions/18342943/serious-bugs-with-lifted-nullable-conversions-from-int-allowing-conversion-from return(new CastResult(value, castFlag)); } return(new CastResult(ex, castFlag)); } catch (Exception ex) { return(new CastResult(ex, castFlag)); } } }
private static string GetCodeline(int index, Type sourceType, Type targetType, CastFlag castFlag) { return(string.Format( "{0} var{1} = {2}Get<{3}>();", targetType.GetFormattedFullname(), index, castFlag == CastFlag.Implicit ? string.Empty : "(" + targetType.GetFormattedFullname() + ")", sourceType.GetFormattedFullname())); }
internal static CastResult CastTo(object value, Type targetType) { if (value == null) { return(new CastResult((object)null, CastFlag.Undefined)); } Guard.ArgumentNotNull(targetType, nameof(targetType)); var sourceType = value.GetType(); var sourceTypeInfo = value.GetType().GetTypeInfo(); var targetTypeInfo = targetType.GetTypeInfo(); if (targetTypeInfo.IsGenericType && !targetTypeInfo.GenericTypeArguments.Any()) { return (new CastResult( ConversionNotSupportedException.Create( sourceType, targetType, string.Format("The target type {0} does not have sufficient generic type arguments specified.", targetType.GetFormattedName())), CastFlag.Undefined)); } CastResult castResult = null; CastFlag castFlag = CastFlag.Undefined; try { // explicit conversion always works if to : from OR if there's an implicit conversion if (targetType.IsSameOrParent(sourceType)) { castFlag = CastFlag.Implicit; var castedValue = GenericCast(() => AttemptImplicitCast <object, object>(null), sourceType, targetType, value); castResult = new CastResult(castedValue, castFlag); } // for nullable types, we can simply strip off the nullability and evaluate the underyling types else if (Nullable.GetUnderlyingType(targetType) != null) { castResult = CastTo(value, Nullable.GetUnderlyingType(targetType)); } else if (sourceTypeInfo.IsValueType) { castFlag = CastFlag.Explicit; var castedValue = GenericCast(() => AttemptExplicitCast <object, object>(null), sourceType, targetType, value); castResult = new CastResult(castedValue, castFlag); } else { // Implicit cast operators have priority in favour of explicit operators // since they should not lose precision. See C# language specification: // https://msdn.microsoft.com/en-us/library/z5z9kes2.aspx var conversionMethods = GetCastOperatorMethods(sourceType, targetType) .OrderByDescending(m => m.Name == "op_Implicit") .ThenByDescending(m => m.ReturnType == targetType || m.ReturnType.GetTypeInfo().IsAssignableFrom(targetTypeInfo)); foreach (var conversionMethod in conversionMethods) { try { var convertedValue = conversionMethod.Invoke(null, new[] { value }); castResult = CastTo(convertedValue, targetType); if (castResult.IsSuccessful) { break; } else { castResult = null; } } catch { } } } } catch (Exception ex) { castResult = new CastResult(ConversionNotSupportedException.Create(sourceType, targetType, ex.InnerException), castFlag); } if (castResult == null) { castResult = new CastResult(ConversionNotSupportedException.Create(sourceType, targetType), castFlag); } return(castResult); }