SchemaTests.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. using System.Text.Json;
  2. using Json.Schema;
  3. using YamlDotNet.RepresentationModel;
  4. namespace Tests.Yaml;
  5. public class SchemaConformanceTests
  6. {
  7. private static JsonSchema LoadSchema(int version)
  8. {
  9. var schemaText = File.ReadAllText($"schemas/schema.v{version}.json");
  10. return JsonSchema.FromText(schemaText);
  11. }
  12. private static JsonElement ConvertYamlToJsonElement(string yaml)
  13. {
  14. // Load YAML into YAML DOM
  15. var yamlStream = new YamlStream();
  16. yamlStream.Load(new StringReader(yaml));
  17. var root = yamlStream.Documents[0].RootNode;
  18. // Convert YAML node → JSON string
  19. var json = ConvertYamlNodeToJson(root);
  20. using var document = JsonDocument.Parse(json);
  21. return document.RootElement.Clone();
  22. }
  23. private static string ConvertYamlNodeToJson(YamlNode node)
  24. {
  25. if (node is YamlScalarNode scalar)
  26. {
  27. // Try numeric
  28. if (int.TryParse(scalar.Value, out var i))
  29. return i.ToString();
  30. if (double.TryParse(scalar.Value, out var d))
  31. return d.ToString(System.Globalization.CultureInfo.InvariantCulture);
  32. if (bool.TryParse(scalar.Value, out var b))
  33. return b.ToString().ToLowerInvariant();
  34. // Otherwise string
  35. return JsonSerializer.Serialize(scalar.Value);
  36. }
  37. if (node is YamlSequenceNode sequence)
  38. {
  39. var items = sequence.Children
  40. .Select(ConvertYamlNodeToJson);
  41. return "[" + string.Join(",", items) + "]";
  42. }
  43. if (node is YamlMappingNode mapping)
  44. {
  45. var props = mapping.Children
  46. .Select(kvp =>
  47. JsonSerializer.Serialize(((YamlScalarNode)kvp.Key).Value)
  48. + ":"
  49. + ConvertYamlNodeToJson(kvp.Value));
  50. return "{" + string.Join(",", props) + "}";
  51. }
  52. return "null";
  53. }
  54. [Theory]
  55. [InlineData(1)]
  56. [InlineData(2)]
  57. public void All_yaml_files_conform_to_schema(int version)
  58. {
  59. // Arrange
  60. var schema = LoadSchema(version);
  61. var yamlFolder = Path.Combine(
  62. AppContext.BaseDirectory,
  63. "TestConfigs",
  64. $"v{version}");
  65. var yamlFiles = Directory
  66. .EnumerateFiles(yamlFolder, "*.yaml", SearchOption.AllDirectories)
  67. .ToList();
  68. Assert.NotEmpty(yamlFiles);
  69. var failures = new List<string>();
  70. // Act
  71. foreach (var file in yamlFiles)
  72. {
  73. var yaml = File.ReadAllText(file);
  74. var jsonNode = ConvertYamlToJsonElement(yaml);
  75. var options = new EvaluationOptions
  76. {
  77. OutputFormat = OutputFormat.Hierarchical };
  78. var result = schema.Evaluate(jsonNode, options);
  79. if (!result.IsValid)
  80. {
  81. var errors = new List<string>();
  82. void CollectErrors(EvaluationResults node)
  83. {
  84. if (node.Errors != null)
  85. {
  86. foreach (var error in node.Errors)
  87. errors.Add($"{error.Key}: {error.Value}");
  88. }
  89. if (node.Details != null)
  90. {
  91. foreach (var child in node.Details)
  92. CollectErrors(child);
  93. }
  94. }
  95. CollectErrors(result);
  96. failures.Add(
  97. $"File: {file}{Environment.NewLine}" +
  98. string.Join(Environment.NewLine, errors));
  99. }
  100. }
  101. // Assert
  102. if (failures.Any())
  103. {
  104. var message = string.Join(
  105. $"{Environment.NewLine}--------------------{Environment.NewLine}",
  106. failures);
  107. Assert.Fail(message);
  108. }
  109. }
  110. }