public void ContractChanges() { ContractEnforcement.ValidateContractContainBreakingChanges( dllName: DllName, baselinePath: OfficialBaselinePath, breakingChangesPath: "DotNetSDKAPIChanges.json"); }
public void PreviewContractChanges() { ContractEnforcement.ValidatePreviewContractContainBreakingChanges( dllName: DllName, officialBaselinePath: OfficialBaselinePath, previewBaselinePath: "DotNetPreviewSDKAPI.json", previewBreakingChangesPath: "DotNetPreviewSDKAPIChanges.json"); }
private static TypeTree BuildTypeTree(TypeTree root, Type[] types) { IEnumerable <Type> subclassTypes = types.Where((type) => type.IsSubclassOf(root.Type)).OrderBy(o => o.FullName, invariantComparer); foreach (Type subclassType in subclassTypes) { root.Subclasses[ContractEnforcement.GenerateNameWithClassAttributes(subclassType)] = ContractEnforcement.BuildTypeTree(new TypeTree(subclassType), types); } IEnumerable <KeyValuePair <string, MemberInfo> > memberInfos = root.Type.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly) .Select(memberInfo => new KeyValuePair <string, MemberInfo>($"{memberInfo.ToString()}{string.Join("-", ContractEnforcement.RemoveDebugSpecificAttributes(memberInfo.CustomAttributes))}", memberInfo)) .OrderBy(o => o.Key, invariantComparer); foreach (KeyValuePair <string, MemberInfo> memberInfo in memberInfos) { List <string> attributes = ContractEnforcement.RemoveDebugSpecificAttributes(memberInfo.Value.CustomAttributes) .Select((customAttribute) => customAttribute.AttributeType.Name) .ToList(); attributes.Sort(invariantComparer); string methodSignature = null; if (memberInfo.Value.MemberType == MemberTypes.Method) { MethodInfo methodInfo = (MethodInfo)memberInfo.Value; methodSignature = ContractEnforcement.GenerateNameWithMethodAttributes(methodInfo); } else if (memberInfo.Value.MemberType == MemberTypes.Property) { PropertyInfo propertyInfo = (PropertyInfo)memberInfo.Value; methodSignature = ContractEnforcement.GenerateNameWithPropertyAttributes(propertyInfo); } else if (memberInfo.Value.MemberType == MemberTypes.Field) { FieldInfo fieldInfo = (FieldInfo)memberInfo.Value; methodSignature = ContractEnforcement.GenerateNameWithFieldAttributes(fieldInfo); } else if (memberInfo.Value.MemberType == MemberTypes.Constructor || memberInfo.Value.MemberType == MemberTypes.Event) { methodSignature = memberInfo.ToString(); } root.Members[ memberInfo.Key ] = new MemberMetadata( memberInfo.Value.MemberType, attributes, methodSignature); } foreach (Type nestedType in root.Type.GetNestedTypes().OrderBy(o => o.FullName)) { root.NestedTypes[ContractEnforcement.GenerateNameWithClassAttributes(nestedType)] = ContractEnforcement.BuildTypeTree(new TypeTree(nestedType), types); } return(root); }
public static string GetCurrentContract(string dllName) { TypeTree locally = new TypeTree(typeof(object)); Assembly assembly = ContractEnforcement.GetAssemblyLocally(dllName); Type[] exportedTypes = assembly.GetExportedTypes(); ContractEnforcement.BuildTypeTree(locally, exportedTypes); string localJson = JsonConvert.SerializeObject(locally, Formatting.Indented); return(localJson); }
public static void ValidateContractContainBreakingChanges( string dllName, string baselinePath, string breakingChangesPath) { string localJson = GetCurrentContract(dllName); File.WriteAllText($"Contracts/{breakingChangesPath}", localJson); string baselineJson = GetBaselineContract(baselinePath); ContractEnforcement.ValidateJsonAreSame(localJson, baselineJson); }
private static string GenerateNameWithPropertyAttributes(PropertyInfo propertyInfo) { string name = $"{propertyInfo};{nameof(propertyInfo.CanRead)}:{(propertyInfo.CanRead ? bool.TrueString : bool.FalseString)};" + $"{nameof(propertyInfo.CanWrite)}:{(propertyInfo.CanWrite ? bool.TrueString : bool.FalseString)};"; MethodInfo getMethodInfo = propertyInfo.GetGetMethod(); if (getMethodInfo != null) { name += ContractEnforcement.GenerateNameWithMethodAttributes(getMethodInfo); } MethodInfo setMethodInfo = propertyInfo.GetSetMethod(); if (setMethodInfo != null) { name += ContractEnforcement.GenerateNameWithMethodAttributes(setMethodInfo); } return(name); }
public static void ValidatePreviewContractContainBreakingChanges( string dllName, string officialBaselinePath, string previewBaselinePath, string previewBreakingChangesPath) { string currentPreviewJson = ContractEnforcement.GetCurrentContract( dllName); JObject currentJObject = JObject.Parse(currentPreviewJson); JObject officialBaselineJObject = JObject.Parse(File.ReadAllText("Contracts/" + officialBaselinePath)); string currentJsonNoOfficialContract = ContractEnforcement.RemoveDuplicateContractElements( localContract: currentJObject, officialContract: officialBaselineJObject); Assert.IsNotNull(currentJsonNoOfficialContract); string baselinePreviewJson = ContractEnforcement.GetBaselineContract(previewBaselinePath); File.WriteAllText($"Contracts/{previewBreakingChangesPath}", currentJsonNoOfficialContract); ContractEnforcement.ValidateJsonAreSame(baselinePreviewJson, currentJsonNoOfficialContract); }
private static TypeTree BuildTypeTree(TypeTree root, Type[] types) { IEnumerable <Type> subclassTypes = types.Where((type) => type.IsSubclassOf(root.Type)).OrderBy(o => o.FullName, invariantComparer); foreach (Type subclassType in subclassTypes) { root.Subclasses[ContractEnforcement.GenerateNameWithClassAttributes(subclassType)] = ContractEnforcement.BuildTypeTree(new TypeTree(subclassType), types); } IEnumerable <KeyValuePair <string, MemberInfo> > memberInfos = root.Type.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly) .Select(memberInfo => new KeyValuePair <string, MemberInfo>($"{memberInfo}{string.Join("-", ContractEnforcement.RemoveDebugSpecificAttributes(memberInfo.CustomAttributes))}", memberInfo)) .OrderBy(o => o.Key, invariantComparer); foreach (KeyValuePair <string, MemberInfo> memberInfo in memberInfos) { List <string> attributes = ContractEnforcement.RemoveDebugSpecificAttributes(memberInfo.Value.CustomAttributes) .Select((customAttribute) => customAttribute.AttributeType.Name) .ToList(); attributes.Sort(invariantComparer); string methodSignature = null; if (memberInfo.Value.MemberType == MemberTypes.Method) { MethodInfo methodInfo = (MethodInfo)memberInfo.Value; methodSignature = ContractEnforcement.GenerateNameWithMethodAttributes(methodInfo); } else if (memberInfo.Value.MemberType == MemberTypes.Property) { PropertyInfo propertyInfo = (PropertyInfo)memberInfo.Value; methodSignature = ContractEnforcement.GenerateNameWithPropertyAttributes(propertyInfo); } else if (memberInfo.Value.MemberType == MemberTypes.Field) { FieldInfo fieldInfo = (FieldInfo)memberInfo.Value; methodSignature = ContractEnforcement.GenerateNameWithFieldAttributes(fieldInfo); } else if (memberInfo.Value.MemberType == MemberTypes.Constructor || memberInfo.Value.MemberType == MemberTypes.Event) { methodSignature = memberInfo.ToString(); } // Certain custom attributes add the following to the string value "d__9" which sometimes changes // based on the .NET SDK version it is being built on. This removes the value to avoid showing // breaking change when there is none. string key = Regex.Replace(memberInfo.Key, @"d__\d+", string.Empty); root.Members[ key ] = new MemberMetadata( memberInfo.Value.MemberType, attributes, methodSignature); } foreach (Type nestedType in root.Type.GetNestedTypes().OrderBy(o => o.FullName)) { root.NestedTypes[ContractEnforcement.GenerateNameWithClassAttributes(nestedType)] = ContractEnforcement.BuildTypeTree(new TypeTree(nestedType), types); } return(root); }