using System; using System.Collections.Generic; using System.IO; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Schema; using System.Linq; namespace PortingAssistant.Client.IntegrationTests.TestUtils { public static class JsonUtils { public static bool ValidateSchema(string jsonFilePath, string schemaFilePath, bool isJArray) { JToken data; if (isJArray) { data = (JArray)JsonConvert.DeserializeObject(File.ReadAllText(jsonFilePath)); } else { data = (JObject)JsonConvert.DeserializeObject(File.ReadAllText(jsonFilePath)); } var schema = JSchema.Parse(File.ReadAllText(schemaFilePath)); IList<string> messages; bool valid = data.IsValid(schema, out messages); // properly validates if (valid == false) { Console.WriteLine("{0} failed validatoin against schema {1}", jsonFilePath, schemaFilePath); Console.WriteLine(string.Join("\n", messages)); } return valid; } public static bool AreTwoJsonFilesEqual( string filePath1, string filePath2, string[] propertiesToBeRemoved) { dynamic jObject1 = JsonConvert.DeserializeObject( File.ReadAllText(filePath1)); dynamic jObject2 = JsonConvert.DeserializeObject( File.ReadAllText(filePath2)); if (!IsNullOrEmpty(propertiesToBeRemoved)) { RemoveProperties(jObject1, propertiesToBeRemoved); RemoveProperties(jObject2, propertiesToBeRemoved); } JObject patch = FindJsonDiff(jObject1, jObject2); Console.WriteLine("---------DIFF-----------"); Console.WriteLine(patch.ToString()); return patch.Count == 0; } public static bool IsJsonFileSubset( string jsonSubsetFilePath, string jsonSupersetFilePath, string[] propertiesToBeRemoved) { dynamic jObjectSubset = JsonConvert.DeserializeObject( File.ReadAllText(jsonSubsetFilePath)); dynamic jObjectSuperset = JsonConvert.DeserializeObject( File.ReadAllText(jsonSupersetFilePath)); if (!IsNullOrEmpty(propertiesToBeRemoved)) { RemoveProperties(jObjectSubset, propertiesToBeRemoved); RemoveProperties(jObjectSuperset, propertiesToBeRemoved); } JObject patch = FindJsonDiff(jObjectSubset, jObjectSuperset); return !patch.ContainsKey("-"); } public static JObject FindJsonDiff(this JToken Current, JToken Model) { var diff = new JObject(); if (JToken.DeepEquals(Current, Model)) return diff; switch (Current.Type) { case JTokenType.Object: { var current = Current as JObject; var model = Model as JObject; var addedKeys = current.Properties().Select(c => c.Name).Except(model.Properties().Select(c => c.Name)); var removedKeys = model.Properties().Select(c => c.Name).Except(current.Properties().Select(c => c.Name)); var unchangedKeys = current.Properties().Where(c => JToken.DeepEquals(c.Value, Model[c.Name])).Select(c => c.Name); foreach (var k in addedKeys) { diff[k] = new JObject { ["+"] = Current[k] }; } foreach (var k in removedKeys) { diff[k] = new JObject { ["-"] = Model[k] }; } var potentiallyModifiedKeys = current.Properties().Select(c => c.Name).Except(addedKeys).Except(unchangedKeys); foreach (var k in potentiallyModifiedKeys) { var foundDiff = FindJsonDiff(current[k], model[k]); if (foundDiff.HasValues) diff[k] = foundDiff; } } break; case JTokenType.Array: { var current = Current as JArray; var model = Model as JArray; var plus = new JArray(current.Except(model, new JTokenEqualityComparer())); var minus = new JArray(model.Except(current, new JTokenEqualityComparer())); if (plus.HasValues) diff["+"] = plus; if (minus.HasValues) diff["-"] = minus; } break; default: diff["+"] = Current; diff["-"] = Model; break; } return diff; } public static bool IsNullOrEmpty(string[] myStringArray) { return myStringArray == null || myStringArray.Length < 1; } private static void RemoveProperties(JToken token, string[] propertiesToBeRemoved) { JContainer container = token as JContainer; if (container == null) return; List<JToken> removeList = new List<JToken>(); foreach (JToken el in container.Children()) { JProperty p = el as JProperty; if (p != null && Array.IndexOf(propertiesToBeRemoved, p.Name) >= 0) { removeList.Add(el); } RemoveProperties(el, propertiesToBeRemoved); } foreach (JToken el in removeList) { el.Remove(); } } } }