add validate as dictionary flag, pass rules as object, modify tests and change some format

This commit is contained in:
NORTHAMERICA\haoqihuang 2021-06-24 08:25:06 -07:00
Родитель da577928c5
Коммит 5637410e28
2 изменённых файлов: 223 добавлений и 158 удалений

Просмотреть файл

@ -3,7 +3,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright> // </copyright>
// <summary> // <summary>
// Tests the TreeSchemaValidator class. // Tests for the TreeSchemaValidator class.
// </summary> // </summary>
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
@ -18,7 +18,6 @@ namespace Microsoft.Forge.TreeWalker.UnitTests
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Schema; using Newtonsoft.Json.Schema;
using Microsoft.Forge.TreeWalker; using Microsoft.Forge.TreeWalker;
using System.Threading.Tasks;
[TestClass] [TestClass]
public class TreeSchemaValidatorTests public class TreeSchemaValidatorTests
@ -53,59 +52,67 @@ namespace Microsoft.Forge.TreeWalker.UnitTests
invalidSchemaWithErrorContent = File.ReadAllText(Path.Combine(Environment.CurrentDirectory, "test\\InvalidTestSchemas\\InvalidTestSchemaErrorContent.json")); invalidSchemaWithErrorContent = File.ReadAllText(Path.Combine(Environment.CurrentDirectory, "test\\InvalidTestSchemas\\InvalidTestSchemaErrorContent.json"));
invalidSchemaDirectoryPath = "test\\ExampleSchemas\\TardigradeSchema.json"; invalidSchemaDirectoryPath = "test\\ExampleSchemas\\TardigradeSchema.json";
} }
[TestMethod] [TestMethod]
public void Test_ValidateSchemaInForgeTreeWithCustomRulesInString() public void Test_ValidateSchemaInForgeTreeWithCustomRulesInString()
{ {
var res = ForgeSchemaValidator.ValidateSchema(treeSchema, stringRules, out List<string> errorList); bool res = ForgeSchemaValidator.ValidateSchema(treeSchema, stringRules, out List<string> errorList);
Assert.AreEqual(true, res); Assert.AreEqual(true, res);
Assert.AreEqual(0, errorList.Count); Assert.AreEqual(0, errorList.Count);
} }
[TestMethod] [TestMethod]
public void Test_ValidateSchemaInForgeTreeWithCustomRulesInJSchema() public void Test_ValidateSchemaInForgeTreeWithCustomRulesInJSchema()
{ {
var res = ForgeSchemaValidator.ValidateSchema(treeSchema, jschemaRules, out List<string> errorList); bool res = ForgeSchemaValidator.ValidateSchema(treeSchema, jschemaRules, out List<string> errorList);
Assert.AreEqual(true, res); Assert.AreEqual(true, res);
Assert.AreEqual(0, errorList.Count); Assert.AreEqual(0, errorList.Count);
} }
[TestMethod] [TestMethod]
public void Test_ValidateSchemaInForgeTreeListWithCustomRulesInString() public void Test_ValidateSchemaInForgeTreeListWithCustomRulesInString()
{ {
var res = ForgeSchemaValidator.ValidateSchema(treeSchema, stringRules, out List<string> errorList); bool res = ForgeSchemaValidator.ValidateSchema(treeSchema, stringRules, out List<string> errorList);
Assert.AreEqual(true, res); Assert.AreEqual(true, res);
Assert.AreEqual(0, errorList.Count); Assert.AreEqual(0, errorList.Count);
} }
[TestMethod] [TestMethod]
public void Test_ValidateSchemaInForgeTreeListWithCustomRulesInJSchema() public void Test_ValidateSchemaInForgeTreeListWithCustomRulesInJSchema()
{ {
var res = ForgeSchemaValidator.ValidateSchema(treeSchema, jschemaRules, out List<string> errorList); bool res = ForgeSchemaValidator.ValidateSchema(treeSchema, jschemaRules, out List<string> errorList);
Assert.AreEqual(true, res); Assert.AreEqual(true, res);
Assert.AreEqual(0, errorList.Count); Assert.AreEqual(0, errorList.Count);
} }
[TestMethod] [TestMethod]
public void Test_ValidateSchemaInStringWithCustomRulesInString() public void Test_ValidateSchemaInStringWithCustomRules()
{ {
var res = ForgeSchemaValidator.ValidateSchemaString(stringSchema, stringRules, out List<string> errorList); bool res = ForgeSchemaValidator.ValidateSchemaString(stringSchema, stringRules, false, out List<string> errorList);
Assert.AreEqual(true, res); Assert.AreEqual(true, res);
Assert.AreEqual(0, errorList.Count); Assert.AreEqual(0, errorList.Count);
} }
[TestMethod] [TestMethod]
public void Test_ValidateSchemaInStringWithCustomRulesInJSchema() public void Test_ValidateSchemaInStringWithCustomRulesInJSchema()
{ {
var res = ForgeSchemaValidator.ValidateSchemaString(stringSchema, jschemaRules, out List<string> errorList); bool res = ForgeSchemaValidator.ValidateSchemaString(stringSchema, jschemaRules, false, out List<string> errorList);
Assert.AreEqual(true, res); Assert.AreEqual(true, res);
Assert.AreEqual(0, errorList.Count); Assert.AreEqual(0, errorList.Count);
} }
[TestMethod] [TestMethod]
public void Test_ValidateSchemasInStringListWithCustomRulesInString() public void Test_ValidateSchemasInStringListWithCustomRulesInString()
{ {
var res = ForgeSchemaValidator.ValidateSchemaString(stringSchemaList, stringRules, out List<string> errorList); bool res = ForgeSchemaValidator.ValidateSchemaString(stringSchemaList, stringRules, false, out List<string> errorList);
Assert.AreEqual(true, res); Assert.AreEqual(true, res);
Assert.AreEqual(0, errorList.Count); Assert.AreEqual(0, errorList.Count);
} }
[TestMethod] [TestMethod]
public void Test_ValidateSchemasInStringListWithCustomRulesInJSchema() public void Test_ValidateSchemasInStringListWithCustomRulesInJSchema()
{ {
var res = ForgeSchemaValidator.ValidateSchemaString(stringSchemaList, jschemaRules, out List<string> errorList); bool res = ForgeSchemaValidator.ValidateSchemaString(stringSchemaList, jschemaRules, false, out List<string> errorList);
Assert.AreEqual(true, res); Assert.AreEqual(true, res);
Assert.AreEqual(0, errorList.Count); Assert.AreEqual(0, errorList.Count);
} }
@ -113,59 +120,96 @@ namespace Microsoft.Forge.TreeWalker.UnitTests
[TestMethod] [TestMethod]
public void Test_ValidateSchemaFromPathWithCustomRulesInString() public void Test_ValidateSchemaFromPathWithCustomRulesInString()
{ {
var res = ForgeSchemaValidator.ValidateSchemaInPath(schemaPath, stringRules, out List<string> errorList); bool res = ForgeSchemaValidator.ValidateSchemaInPath(schemaPath, stringRules, false, out List<string> errorList);
Assert.AreEqual(true, res); Assert.AreEqual(true, res);
Assert.AreEqual(0, errorList.Count); Assert.AreEqual(0, errorList.Count);
} }
[TestMethod] [TestMethod]
public void Test_ValidateSchemaFromPathWithCustomRulesInJSchema() public void Test_ValidateSchemaFromPathWithCustomRulesInJSchema()
{ {
var res = ForgeSchemaValidator.ValidateSchemaInPath(schemaPath, jschemaRules, out List<string> errorList); bool res = ForgeSchemaValidator.ValidateSchemaInPath(schemaPath, jschemaRules, false, out List<string> errorList);
Assert.AreEqual(true, res); Assert.AreEqual(true, res);
Assert.AreEqual(0, errorList.Count); Assert.AreEqual(0, errorList.Count);
} }
[TestMethod] [TestMethod]
public void Test_ValidateSchemasFromDirectoryListWithCustomRulesInString() public void Test_ValidateSchemasFromDirectoryListWithCustomRulesInString()
{ {
var res = ForgeSchemaValidator.ValidateMultipleSchemasInPath(schemaDirectoryPath, stringRules, out List<string> errorList); bool res = ForgeSchemaValidator.ValidateMultipleSchemasInPath(schemaDirectoryPath, stringRules, false, out List<string> errorList);
Assert.AreEqual(true, res); Assert.AreEqual(true, res);
Assert.AreEqual(0, errorList.Count); Assert.AreEqual(0, errorList.Count);
} }
[TestMethod] [TestMethod]
public void Test_ValidateSchemasFromDirectoryListWithCustomRulesInJSchema() public void Test_ValidateSchemasFromDirectoryListWithCustomRulesInJSchema()
{ {
var res = ForgeSchemaValidator.ValidateMultipleSchemasInPath(schemaDirectoryPath, jschemaRules, out List<string> errorList); bool res = ForgeSchemaValidator.ValidateMultipleSchemasInPath(schemaDirectoryPath, jschemaRules, false, out List<string> errorList);
Assert.AreEqual(true, res); Assert.AreEqual(true, res);
Assert.AreEqual(0, errorList.Count); Assert.AreEqual(0, errorList.Count);
} }
[TestMethod] [TestMethod]
public void Test_ValidateInvalidSchemaInString() public void Test_ValidateInvalidSchemaInString()
{ {
var res = ForgeSchemaValidator.ValidateSchemaString(invalidSchemaNotTree, jschemaRules, out List<string> errorList); bool res = ForgeSchemaValidator.ValidateSchemaString(stringSchema, jschemaRules, false, out List<string> errorList);
Assert.AreEqual(false, res); Assert.AreEqual(true, res);
Assert.AreEqual("Required property 'Type' not found in JSON. Path 'Tree.Root', line 5, position 9.", errorList.First()); Assert.AreEqual(0, errorList.Count);
} }
[TestMethod] [TestMethod]
public void Test_ValidateInvalidSchemaDirectoryPath() public void Test_ValidateInvalidSchemaDirectoryPath()
{ {
var res = ForgeSchemaValidator.ValidateMultipleSchemasInPath(invalidSchemaDirectoryPath, jschemaRules,out List<string> errorList); bool res = ForgeSchemaValidator.ValidateMultipleSchemasInPath(invalidSchemaDirectoryPath, jschemaRules, false, out List<string> errorList);
Assert.AreEqual(false, res); Assert.AreEqual(false, res);
Assert.AreEqual("The directory name is invalid.\r\n", errorList.First()); Assert.AreEqual("The directory name is invalid.\r\n", errorList.First());
} }
[TestMethod] [TestMethod]
public void Test_ValidateSchemaWithErrorContent() public void Test_ValidateSchemaWithErrorContent()
{ {
var res = ForgeSchemaValidator.ValidateSchemaString(invalidSchemaWithErrorContent, jschemaRules, out List<string> errorList); bool res = ForgeSchemaValidator.ValidateSchemaString(invalidSchemaWithErrorContent, jschemaRules, false, out List<string> errorList);
Assert.AreEqual(false, res); Assert.AreEqual(false, res);
Assert.AreEqual("JSON is valid against no schemas from 'oneOf'. line: 3, position: 17", errorList.First()); Assert.AreEqual("JSON is valid against no schemas from 'oneOf'. line: 3, position: 17", errorList.First());
} }
[TestMethod]
public void Test_ValidateInvalidSchemaAsDictionary()
{
bool res = ForgeSchemaValidator.ValidateSchemaString(invalidSchemaWithErrorContent, jschemaRules, true, out List<string> errorList);
Assert.AreEqual(false, res);
Assert.AreEqual("JSON is valid against no schemas from 'oneOf'. line: 3, position: 17", errorList.First());
}
[TestMethod]
public void Test_ValidateValidSchemaAsDictionary()
{
bool res = ForgeSchemaValidator.ValidateSchemaString(invalidSchemaWithErrorContent, jschemaRules, true, out List<string> errorList);
Assert.AreEqual(false, res);
Assert.AreEqual("JSON is valid against no schemas from 'oneOf'. line: 3, position: 17", errorList.First());
}
[TestMethod]
public void Test_ValidateSchemasFromDirectoryListAsDictionaryWithCustomRulesInString()
{
bool res = ForgeSchemaValidator.ValidateMultipleSchemasInPath(schemaDirectoryPath, stringRules, true, out List<string> errorList);
Assert.AreEqual(false, res);
Assert.AreEqual("An item with the same key has already been added.", errorList.First());
}
[TestMethod] [TestMethod]
public void Test_GetLinkedJSchemaRules() public void Test_GetLinkedJSchemaRules()
{ {
var linkedRules = ForgeSchemaValidator.GetLinkedJSchemaRules(stringRules, stringRules, "//ForgeSchemaValidationRules.json", out string error); try
Assert.AreEqual("", error); {
ForgeSchemaValidator.ValidateSchema(treeSchema, linkedRules, out List<string> errorList); JSchema linkedRules = ForgeSchemaValidator.GetLinkedJSchemaRules(stringRules, stringRules, "//ForgeSchemaValidationRules.json");
Assert.AreEqual(0, errorList.Count); ForgeSchemaValidator.ValidateSchema(treeSchema, linkedRules, out List<string> errorList);
Assert.AreEqual(0, errorList.Count);
}
catch (Exception ex)
{
Assert.Fail("Expected no exception, but got: " + ex.Message);
}
} }
} }
} }

Просмотреть файл

@ -3,200 +3,170 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright> // </copyright>
// <summary> // <summary>
// The ForgeSchemaValidator class implements the ITreeSchemaValidator interface. // The ForgeSchemaValidator class.
// </summary> // </summary>
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
namespace Microsoft.Forge.TreeWalker namespace Microsoft.Forge.TreeWalker
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading.Tasks;
using Microsoft.Forge.DataContracts; using Microsoft.Forge.DataContracts;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema; using Newtonsoft.Json.Schema;
/// <summary> /// <summary>
/// The ForgeSchemaValidator class implements the validation method that tests input schemas with custom rules from input. /// The ForgeSchemaValidator class implements the validation method that tests input schemas with input custom rules.
/// </summary> /// </summary>
public static class ForgeSchemaValidator public static class ForgeSchemaValidator
{ {
/// <summary> /// <summary>
/// The GetLinkedJSchema method that creates the linked rules in JSchema. /// Linked rules in JSchema type.
/// </summary> /// </summary>
/// <param name="childRules">The rules to be included in the parent rules</param> /// <param name="childRules">The rules to be included in the parent rules</param>
/// <param name="parentRules">The parent rules to absorb the child rules</param> /// <param name="parentRules">The parent rules to absorb the child rules</param>
/// <param name="referenceUri">The address of childRules</param> /// <param name="referenceUri">The address of childRules</param>
/// <returns>The result of schema combination. ErrorMessage would be set if it throw exceptions</returns> /// <returns>The result of schema combination.</returns>
public static JSchema GetLinkedJSchemaRules(string childRules, string parentRules, string referenceUri, out string errorMessage) public static JSchema GetLinkedJSchemaRules(string childRules, string parentRules, string referenceUri)
{ {
try JSchemaPreloadedResolver resolver = new JSchemaPreloadedResolver();
{ resolver.Add(new Uri(referenceUri), childRules);
JSchemaPreloadedResolver resolver = new JSchemaPreloadedResolver();
resolver.Add(new Uri(referenceUri), childRules); return JSchema.Parse(parentRules, resolver);
errorMessage = "";
return JSchema.Parse(parentRules, resolver);
}
catch(Exception e)
{
errorMessage = e.Message;
return null;
}
} }
/// <summary> /// <summary>
/// The validate task that validate the input schema with custom rules in string. /// Validates the ForgeTree schema with the given rules.
/// </summary> /// </summary>
/// <param name="schema">The schema to be validated</param> /// <param name="schema">The schema to be validated</param>
/// <param name="rules">The rules used to validate input schemas</param> /// <param name="rules">The rules used to validate input schemas is only allowed in string or JSchema type</param>
/// <returns>The result of schema validation. The errorList would contain error message if validation fails</returns> /// /// <returns>The result of schema validation. The errorList would contain error message if validation fails</returns>
public static bool ValidateSchema(ForgeTree schema, string rules, out List<string> errorList) public static bool ValidateSchema(ForgeTree schema, object rules, out List<string> errorList)
{ {
return Validate(new List<JObject> { SerializeForgeTree(schema) }, JSchema.Parse(rules), out errorList); return Validate(new List<JObject> { SerializeToJObject(schema) }, rules, out errorList);
} }
/// <summary> /// <summary>
/// The validate task that validate the input schema with custom rules in string. /// Validates single or multiple schemas in Dictionary with the given rules.
/// </summary>
/// <param name="schema">The schema to be validated</param>
/// <param name="rules">The rules used to validate input schemas</param>
/// <returns>The result of schema validation. The errorList would contain error message if validation fails</returns>
public static bool ValidateSchema(ForgeTree schema, JSchema rules, out List<string> errorList)
{
return Validate(new List<JObject> { SerializeForgeTree(schema) }, rules, out errorList);
}
/// <summary>
/// The validate task that validate multiple input schemas with custom rules in string.
/// </summary> /// </summary>
/// <param name="schemas">The schemas to be validated</param> /// <param name="schemas">The schemas to be validated</param>
/// <param name="rules">The rules used to validate input schemas</param> /// <param name="rules">The rules used to validate input schemas is only allowed in string or JSchema type</param>
/// <param name="validateAsDictionary">True if the custom rules is to handle the whole dictionary</param>
/// <returns>The result of schema validation. The errorList would contain error message if validation fails</returns> /// <returns>The result of schema validation. The errorList would contain error message if validation fails</returns>
public static bool ValidateSchemas(Dictionary<string, ForgeTree> schemas, string rules, out List<string> errorList) public static bool ValidateSchemas(Dictionary<string, ForgeTree> schemas, object rules, bool validateAsDictionary, out List<string> errorList)
{ {
return Validate(ConvertDictionaryToForgeTreeList(schemas), JSchema.Parse(rules), out errorList); return Validate(ConvertDictionaryToJObjectList(schemas, validateAsDictionary), rules, out errorList);
} }
/// <summary> /// <summary>
/// The validate task that check the input schema in string with custom rules in string. /// Validates single or multiple schemas in string with the given rules.
/// </summary> /// </summary>
/// <param name="schema">The schema to be validated</param> /// <param name="schema">The schema to be validated</param>
/// <param name="rules">The rules used to validate input schemas</param> /// <param name="rules">The rules used to validate input schemas is only allowed in string or JSchema type</param>
/// <param name="validateAsDictionary">True if the custom rules is to handle the whole dictionary</param>
/// <returns>The result of schema validation. The errorList would contain error message if validation fails</returns> /// <returns>The result of schema validation. The errorList would contain error message if validation fails</returns>
public static bool ValidateSchemaString(string schema, string rules, out List<string> errorList) public static bool ValidateSchemaString(string schema, object rules, bool validateAsDictionary, out List<string> errorList)
{ {
var schemaList = ConvertStringToJObjectList(schema, out errorList); List<JObject> schemaList = ConvertStringToJObjectList(schema, out errorList, validateAsDictionary);
return CheckConvertErrorAndValidate(JSchema.Parse(rules), ref errorList, schemaList);
return CheckConvertErrorAndValidate(rules, ref errorList, schemaList);
} }
/// <summary> /// <summary>
/// The validate task that validate the schema in the input file path with custom rules in string. /// Validates single or multiple schemas from input path with the given rules.
/// </summary> /// </summary>
/// <param name="path">The path that contains a schema file</param> /// <param name="path">The path that contains a schema file</param>
/// <param name="rules">The rules used to validate input schemas</param> /// <param name="rules">The rules used to validate input schemas is only allowed in string or JSchema type</param>
/// <param name="validateAsDictionary">True if the custom rules is to handle the whole dictionary</param>
/// <returns>The result of schema validation. The errorList would contain error message if validation fails</returns> /// <returns>The result of schema validation. The errorList would contain error message if validation fails</returns>
public static bool ValidateSchemaInPath(string path, string rules, out List<string> errorList) public static bool ValidateSchemaInPath(string path, object rules, bool validateAsDictionary, out List<string> errorList)
{ {
var schemas = GetSchemaFromPath(path, out errorList); List<JObject> schemas = GetSchemaFromPath(path, out errorList, validateAsDictionary);
return CheckConvertErrorAndValidate(JSchema.Parse(rules), ref errorList, schemas);
}
/// <summary>
/// The validate task that validate all schemas in a directory with custom rules in string.
/// </summary>
/// <param name="path">The path that contains a schemas directory</param>
/// <param name="rules">The rules used to validate input schemas</param>
/// <returns>The result of schema validation. The errorList would contain error message if validation fails</returns>
public static bool ValidateMultipleSchemasInPath(string path, string rules, out List<string> errorList)
{
var schemas = GetAllSchemasInDirectory(path, out errorList);
return CheckConvertErrorAndValidate(JSchema.Parse(rules), ref errorList, schemas);
}
/// <summary>
/// The validate task that validate multiple input schemas with custom rules in JSchema.
/// </summary>
/// <param name="schemas">The schemas to be validated</param>
/// <param name="rules">The rules used to validate input schemas</param>
/// <returns>The result of schema validation. The errorList would contain error message if validation fails</returns>
public static bool ValidateSchemas(Dictionary<string, ForgeTree> schemas, JSchema rules, out List<string> errorList)
{
return Validate(ConvertDictionaryToForgeTreeList(schemas), rules, out errorList);
}
/// <summary>
/// The validate task that validate the schema in the input file path with custom rules in JSchema.
/// </summary>
/// <param name="path">The path that contains a schema file</param>
/// <param name="rules">The rules used to validate input schemas</param>
/// <returns>The result of schema validation. The errorList would contain error message if validation fails</returns>
public static bool ValidateSchemaInPath(string path, JSchema rules, out List<string> errorList)
{
var schema = GetSchemaFromPath(path, out errorList);
return CheckConvertErrorAndValidate(rules, ref errorList, schema);
}
/// <summary>
/// The validate task that validate all schemas in a directory with custom rules in JSchema.
/// </summary>
/// <param name="path">The path that contains a schemas directory</param>
/// <param name="rules">The rules used to validate input schemas</param>
/// <returns>The result of schema validation. The errorList would contain error message if validation fails</returns>
public static bool ValidateMultipleSchemasInPath(string path, JSchema rules, out List<string> errorList)
{
var schemas = GetAllSchemasInDirectory(path, out errorList);
return CheckConvertErrorAndValidate(rules, ref errorList, schemas); return CheckConvertErrorAndValidate(rules, ref errorList, schemas);
} }
/// <summary> /// <summary>
/// The validate task that check the input schema in string with custom rules in JSchema. /// Validates single or multiple schemas from input path with the given rules.
/// </summary> /// </summary>
/// <param name="schema">The schema to be validated</param> /// <param name="path">The path that contains a schemas directory</param>
/// <param name="rules">The rules used to validate input schemas</param> /// <param name="rules">The rules used to validate input schemas is only allowed in string or JSchema type</param>
/// <param name="validateAsDictionary">True if the custom rules is to handle the whole dictionary</param>
/// <returns>The result of schema validation. The errorList would contain error message if validation fails</returns> /// <returns>The result of schema validation. The errorList would contain error message if validation fails</returns>
public static bool ValidateSchemaString(string schema, JSchema rules, out List<string> errorList) public static bool ValidateMultipleSchemasInPath(string path, object rules, bool validateAsDictionary, out List<string> errorList)
{ {
var schemaList = ConvertStringToJObjectList(schema, out errorList); List<JObject> schemas = GetAllSchemasInDirectory(path, out errorList, validateAsDictionary);
if (errorList.Count > 0)
{ return CheckConvertErrorAndValidate(rules, ref errorList, schemas);
return false;
}
var res = Validate(schemaList, rules, out errorList);
return res;
} }
private static List<JObject> ConvertDictionaryToForgeTreeList(Dictionary<string, ForgeTree> schemas)
private static List<JObject> ConvertDictionaryToJObjectList(Dictionary<string, ForgeTree> schemas, bool validateAsDictionary)
{ {
var schemaList = new List<JObject>(); List<JObject> schemaList = new List<JObject>();
foreach (var item in schemas.Values)
schemaList.Add(SerializeForgeTree(item)); if (validateAsDictionary)
{
schemaList.Add(SerializeToJObject(schemas));
}
else
{
foreach (ForgeTree item in schemas.Values)
{
schemaList.Add(SerializeToJObject(item));
}
}
return schemaList; return schemaList;
} }
private static List<JObject> ConvertStringToJObjectList(string schema, out List<string> errorList) private static List<JObject> ConvertStringToJObjectList(string schema, out List<string> errorList, bool validateAsDictionary)
{ {
var schemaList = new List<JObject>(); List<JObject> schemaList = new List<JObject>();
errorList = new List<string>(); errorList = new List<string>();
try try
{ {
//There could be three possible cases:
//1. TreeName mapped to the ForgeTree in the dictionary and custom rules handle dictionary.
//2. There are only ForgeTree without matching forge tree name custom rules handle ForgeTree list.
Dictionary<string, ForgeTree> forgeTrees = JsonConvert.DeserializeObject<Dictionary<string, ForgeTree>>(schema); Dictionary<string, ForgeTree> forgeTrees = JsonConvert.DeserializeObject<Dictionary<string, ForgeTree>>(schema);
foreach (var kvp in forgeTrees)
if (validateAsDictionary)
{ {
ForgeTree forgeTree = kvp.Value; schemaList.Add(JObject.Parse(schema));
if (forgeTree.Tree == null) }
else
{
foreach (KeyValuePair<string, ForgeTree> kvp in forgeTrees)
{ {
// Deserialize into Dictionary does not throw exception but will have null "Tree" property if schema is just a ForgeTree. ForgeTree forgeTree = kvp.Value;
// try to deserialize string to forge tree directly
JsonConvert.DeserializeObject<ForgeTree>(schema); if (forgeTree.Tree == null)
JObject res = JObject.Parse(schema); {
schemaList.Add(res); // Deserialize into Dictionary does not throw exception but will have null "Tree" property if schema is just a ForgeTree.
break; // try to deserialize string to forge tree directly
JsonConvert.DeserializeObject<ForgeTree>(schema);
schemaList.Add(JObject.Parse(schema));
break;
}
schemaList.Add(SerializeToJObject(forgeTree));
} }
schemaList.Add(SerializeForgeTree(forgeTree));
} }
} }
catch (Exception e) catch (Exception e)
{ {
errorList.Add(e.Message); errorList.Add(e.Message);
} }
return schemaList; return schemaList;
} }
private static JObject SerializeForgeTree(ForgeTree forgeTree) private static JObject SerializeToJObject(object forgeTree)
{ {
string stringSchema = JsonConvert.SerializeObject( string stringSchema = JsonConvert.SerializeObject(
forgeTree, forgeTree,
@ -205,79 +175,130 @@ namespace Microsoft.Forge.TreeWalker
DefaultValueHandling = DefaultValueHandling.Ignore, // Prevent default values from getting added to serialized json schema. DefaultValueHandling = DefaultValueHandling.Ignore, // Prevent default values from getting added to serialized json schema.
Converters = new List<JsonConverter> { new Newtonsoft.Json.Converters.StringEnumConverter() } // Use string enum values instead of numerical. Converters = new List<JsonConverter> { new Newtonsoft.Json.Converters.StringEnumConverter() } // Use string enum values instead of numerical.
}); });
return JObject.Parse(stringSchema); return JObject.Parse(stringSchema);
} }
private static List<JObject> GetSchemaFromPath(string path, out List<string> errorList) private static List<JObject> GetSchemaFromPath(string path, out List<string> errorList, bool validateAsDictionary)
{ {
errorList = new List<string>(); errorList = new List<string>();
try try
{ {
var schema = File.ReadAllText(path); string schema = File.ReadAllText(path);
var res = ConvertStringToJObjectList(schema, out List<string> convertError);
List<JObject> res = ConvertStringToJObjectList(schema, out List<string> convertError, validateAsDictionary);
errorList = convertError; errorList = convertError;
return res; return res;
} }
catch (Exception e) catch (Exception e)
{ {
errorList.Add(e.Message); errorList.Add(e.Message);
return new List<JObject>(); return new List<JObject>();
} }
} }
private static List<JObject> GetAllSchemasInDirectory(string path, out List<string> errorList) private static List<JObject> GetAllSchemasInDirectory(string path, out List<string> errorList, bool validateAsDictionary)
{ {
var schemaList = new List<JObject>(); List<JObject> schemaList = new List<JObject>();
errorList = new List<string>(); errorList = new List<string>();
try try
{ {
string[] Files = Directory.GetFiles(path); string[] Files = Directory.GetFiles(path);
var schemalist = new List<object>(); List<object> schemalist = new List<object>();
foreach (string file in Files)
{ if (validateAsDictionary) {
var schemasInFile = GetSchemaFromPath(file, out errorList); Dictionary<string, ForgeTree> combinedDictionary = new Dictionary<string, ForgeTree>();
if (errorList.Count > 0)
foreach (string file in Files)
{ {
break; string schema = File.ReadAllText(file);
Dictionary<string, ForgeTree> schemaDictionary = JsonConvert.DeserializeObject<Dictionary<string, ForgeTree>>(schema);
foreach (KeyValuePair<string, ForgeTree> item in schemaDictionary)
{
combinedDictionary.Add(item.Key, item.Value);
}
}
return new List<JObject> { SerializeToJObject(combinedDictionary) };
}
else
{
foreach (string file in Files)
{
List<JObject> schemasInFile = GetSchemaFromPath(file, out errorList, validateAsDictionary);
if (errorList.Count > 0)
{
break;
}
schemasInFile.ForEach(n => schemaList.Add(n));
} }
schemasInFile.ForEach(n => schemaList.Add(n));
} }
} }
catch (Exception e) catch (Exception e)
{ {
errorList.Add(e.Message); errorList.Add(e.Message);
} }
return schemaList; return schemaList;
} }
private static bool CheckConvertErrorAndValidate(JSchema rules, ref List<string> errorList, List<JObject> schemaList) private static bool CheckConvertErrorAndValidate(Object rules, ref List<string> errorList, List<JObject> schemaList)
{ {
if (errorList.Count > 0) if (errorList.Count > 0)
{ {
return false; return false;
} }
return Validate(schemaList, rules, out errorList); return Validate(schemaList, rules, out errorList);
} }
private static bool Validate(List<JObject> schemas, JSchema rules, out List<string> errorList) private static bool Validate(List<JObject> schemas, Object rules, out List<string> errorList)
{ {
errorList = new List<string>(); errorList = new List<string>();
JSchema jSchemaRules = null;
if (rules is string)
{
jSchemaRules = JSchema.Parse((string)rules);
}
else if (rules is JSchema)
{
jSchemaRules = (JSchema)rules;
}
else
{
errorList.Add("Rules type could only be string or JSchema");
return false;
}
if (schemas.Count == 0) if (schemas.Count == 0)
{ {
errorList.Add("Can't find target schema to test or file type is not supported"); errorList.Add("Can't find target schema to test or file type is not supported");
return false; return false;
} }
foreach (var schema in schemas)
foreach (JObject schema in schemas)
{ {
if (!schema.IsValid(rules, out IList<ValidationError> errorDetail)) if (!schema.IsValid(jSchemaRules, out IList<ValidationError> errorDetail))
{ {
foreach (var error in errorDetail) foreach (ValidationError error in errorDetail)
{ {
errorList.Add(error.Message + " line: " + error.LineNumber + ", position: " + error.LinePosition); errorList.Add(error.Message + " line: " + error.LineNumber + ", position: " + error.LinePosition);
} }
return false; return false;
} }
} }
return true; return true;
} }
} }