1 #region License 2 // Copyright (c) 2007 James Newton-King 3 // 4 // Permission is hereby granted, free of charge, to any person 5 // obtaining a copy of this software and associated documentation 6 // files (the "Software"), to deal in the Software without 7 // restriction, including without limitation the rights to use, 8 // copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the 10 // Software is furnished to do so, subject to the following 11 // conditions: 12 // 13 // The above copyright notice and this permission notice shall be 14 // included in all copies or substantial portions of the Software. 15 // 16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 // OTHER DEALINGS IN THE SOFTWARE. 24 #endregion 25 26 using System; 27 using System.Collections.Generic; 28 #if !NETFX_CORE 29 using NUnit.Framework; 30 #else 31 using Microsoft.VisualStudio.TestTools.UnitTesting; 32 using TestFixture = Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute; 33 using Test = Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute; 34 #endif 35 using Newtonsoft.Json.Schema; 36 using Newtonsoft.Json.Linq; 37 using System.IO; 38 using Newtonsoft.Json.Tests.TestObjects; 39 #if !(SILVERLIGHT || NETFX_CORE) 40 using System.Data; 41 #endif 42 43 namespace Newtonsoft.Json.Tests.Schema 44 { 45 [TestFixture] 46 public class ExtensionsTests : TestFixtureBase 47 { 48 [Test] IsValid()49 public void IsValid() 50 { 51 JsonSchema schema = JsonSchema.Parse("{'type':'integer'}"); 52 JToken stringToken = JToken.FromObject("pie"); 53 JToken integerToken = JToken.FromObject(1); 54 55 IList<string> errorMessages; 56 Assert.AreEqual(true, integerToken.IsValid(schema)); 57 Assert.AreEqual(true, integerToken.IsValid(schema, out errorMessages)); 58 Assert.AreEqual(0, errorMessages.Count); 59 60 Assert.AreEqual(false, stringToken.IsValid(schema)); 61 Assert.AreEqual(false, stringToken.IsValid(schema, out errorMessages)); 62 Assert.AreEqual(1, errorMessages.Count); 63 Assert.AreEqual("Invalid type. Expected Integer but got String.", errorMessages[0]); 64 } 65 66 [Test] ValidateWithEventHandler()67 public void ValidateWithEventHandler() 68 { 69 JsonSchema schema = JsonSchema.Parse("{'pattern':'lol'}"); 70 JToken stringToken = JToken.FromObject("pie lol"); 71 72 List<string> errors = new List<string>(); 73 stringToken.Validate(schema, (sender, args) => errors.Add(args.Message)); 74 Assert.AreEqual(0, errors.Count); 75 76 stringToken = JToken.FromObject("pie"); 77 78 stringToken.Validate(schema, (sender, args) => errors.Add(args.Message)); 79 Assert.AreEqual(1, errors.Count); 80 81 Assert.AreEqual("String 'pie' does not match regex pattern 'lol'.", errors[0]); 82 } 83 84 [Test] ValidateWithOutEventHandlerFailure()85 public void ValidateWithOutEventHandlerFailure() 86 { 87 ExceptionAssert.Throws<JsonSchemaException>(@"String 'pie' does not match regex pattern 'lol'.", 88 () => 89 { 90 JsonSchema schema = JsonSchema.Parse("{'pattern':'lol'}"); 91 JToken stringToken = JToken.FromObject("pie"); 92 stringToken.Validate(schema); 93 }); 94 } 95 96 [Test] ValidateWithOutEventHandlerSuccess()97 public void ValidateWithOutEventHandlerSuccess() 98 { 99 JsonSchema schema = JsonSchema.Parse("{'pattern':'lol'}"); 100 JToken stringToken = JToken.FromObject("pie lol"); 101 stringToken.Validate(schema); 102 } 103 104 [Test] ValidateFailureWithOutLineInfoBecauseOfEndToken()105 public void ValidateFailureWithOutLineInfoBecauseOfEndToken() 106 { 107 JsonSchema schema = JsonSchema.Parse("{'properties':{'lol':{'required':true}}}"); 108 JObject o = JObject.Parse("{}"); 109 110 List<string> errors = new List<string>(); 111 o.Validate(schema, (sender, args) => errors.Add(args.Message)); 112 113 Assert.AreEqual("Required properties are missing from object: lol.", errors[0]); 114 Assert.AreEqual(1, errors.Count); 115 } 116 117 [Test] ValidateFailureWithLineInfo()118 public void ValidateFailureWithLineInfo() 119 { 120 JsonSchema schema = JsonSchema.Parse("{'properties':{'lol':{'type':'string'}}}"); 121 JObject o = JObject.Parse("{'lol':1}"); 122 123 List<string> errors = new List<string>(); 124 o.Validate(schema, (sender, args) => errors.Add(args.Path + " - " + args.Message)); 125 126 Assert.AreEqual("lol - Invalid type. Expected String but got Integer. Line 1, position 8.", errors[0]); 127 Assert.AreEqual("1", o.SelectToken("lol").ToString()); 128 Assert.AreEqual(1, errors.Count); 129 } 130 131 [Test] Blog()132 public void Blog() 133 { 134 string schemaJson = @" 135 { 136 ""description"": ""A person schema"", 137 ""type"": ""object"", 138 ""properties"": 139 { 140 ""name"": {""type"":""string""}, 141 ""hobbies"": { 142 ""type"": ""array"", 143 ""items"": {""type"":""string""} 144 } 145 } 146 } 147 "; 148 149 //JsonSchema schema; 150 151 //using (JsonTextReader reader = new JsonTextReader(new StringReader(schemaJson))) 152 //{ 153 // JsonSchemaBuilder builder = new JsonSchemaBuilder(new JsonSchemaResolver()); 154 // schema = builder.Parse(reader); 155 //} 156 157 JsonSchema schema = JsonSchema.Parse(schemaJson); 158 159 JObject person = JObject.Parse(@"{ 160 ""name"": ""James"", 161 ""hobbies"": ["".NET"", ""Blogging"", ""Reading"", ""Xbox"", ""LOLCATS""] 162 }"); 163 164 bool valid = person.IsValid(schema); 165 // true 166 } 167 GenerateSchemaAndSerializeFromType(T value)168 private void GenerateSchemaAndSerializeFromType<T>(T value) 169 { 170 JsonSchemaGenerator generator = new JsonSchemaGenerator(); 171 generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseAssemblyQualifiedName; 172 JsonSchema typeSchema = generator.Generate(typeof (T)); 173 string schema = typeSchema.ToString(); 174 175 string json = JsonConvert.SerializeObject(value, Formatting.Indented); 176 JToken token = JToken.ReadFrom(new JsonTextReader(new StringReader(json))); 177 178 List<string> errors = new List<string>(); 179 180 token.Validate(typeSchema, (sender, args) => 181 { 182 errors.Add(args.Message); 183 }); 184 185 if (errors.Count > 0) 186 Assert.Fail("Schema generated for type '{0}' is not valid." + Environment.NewLine + string.Join(Environment.NewLine, errors.ToArray()), typeof(T)); 187 } 188 189 [Test] GenerateSchemaAndSerializeFromTypeTests()190 public void GenerateSchemaAndSerializeFromTypeTests() 191 { 192 GenerateSchemaAndSerializeFromType(new List<string> { "1", "Two", "III" }); 193 GenerateSchemaAndSerializeFromType(new List<int> { 1 }); 194 GenerateSchemaAndSerializeFromType(new Version("1.2.3.4")); 195 GenerateSchemaAndSerializeFromType(new Store()); 196 GenerateSchemaAndSerializeFromType(new Person()); 197 GenerateSchemaAndSerializeFromType(new PersonRaw()); 198 GenerateSchemaAndSerializeFromType(new CircularReferenceClass() { Name = "I'm required" }); 199 GenerateSchemaAndSerializeFromType(new CircularReferenceWithIdClass()); 200 GenerateSchemaAndSerializeFromType(new ClassWithArray()); 201 GenerateSchemaAndSerializeFromType(new ClassWithGuid()); 202 #if !NET20 && !PocketPC 203 GenerateSchemaAndSerializeFromType(new NullableDateTimeTestClass()); 204 #endif 205 #if !(SILVERLIGHT || NETFX_CORE) 206 GenerateSchemaAndSerializeFromType(new DataSet()); 207 #endif 208 GenerateSchemaAndSerializeFromType(new object()); 209 GenerateSchemaAndSerializeFromType(1); 210 GenerateSchemaAndSerializeFromType("Hi"); 211 GenerateSchemaAndSerializeFromType(new DateTime(2000, 12, 29, 23, 59, 0, DateTimeKind.Utc)); 212 GenerateSchemaAndSerializeFromType(TimeSpan.FromTicks(1000000)); 213 #if !NETFX_CORE 214 GenerateSchemaAndSerializeFromType(DBNull.Value); 215 #endif 216 GenerateSchemaAndSerializeFromType(new JsonPropertyWithHandlingValues()); 217 } 218 219 [Test] UndefinedPropertyOnNoPropertySchema()220 public void UndefinedPropertyOnNoPropertySchema() 221 { 222 JsonSchema schema = JsonSchema.Parse(@"{ 223 ""description"": ""test"", 224 ""type"": ""object"", 225 ""additionalProperties"": false, 226 ""properties"": { 227 } 228 }"); 229 230 JObject o = JObject.Parse("{'g':1}"); 231 232 List<string> errors = new List<string>(); 233 o.Validate(schema, (sender, args) => errors.Add(args.Message)); 234 235 Assert.AreEqual(1, errors.Count); 236 Assert.AreEqual("Property 'g' has not been defined and the schema does not allow additional properties. Line 1, position 5.", errors[0]); 237 } 238 239 [Test] ExclusiveMaximum_Int()240 public void ExclusiveMaximum_Int() 241 { 242 ExceptionAssert.Throws<JsonSchemaException>("Integer 10 equals maximum value of 10 and exclusive maximum is true.", 243 () => 244 { 245 JsonSchema schema = new JsonSchema(); 246 schema.Maximum = 10; 247 schema.ExclusiveMaximum = true; 248 249 JValue v = new JValue(10); 250 v.Validate(schema); 251 }); 252 } 253 254 [Test] ExclusiveMaximum_Float()255 public void ExclusiveMaximum_Float() 256 { 257 ExceptionAssert.Throws<JsonSchemaException>("Float 10.1 equals maximum value of 10.1 and exclusive maximum is true.", 258 () => 259 { 260 JsonSchema schema = new JsonSchema(); 261 schema.Maximum = 10.1; 262 schema.ExclusiveMaximum = true; 263 264 JValue v = new JValue(10.1); 265 v.Validate(schema); 266 }); 267 } 268 269 [Test] ExclusiveMinimum_Int()270 public void ExclusiveMinimum_Int() 271 { 272 ExceptionAssert.Throws<JsonSchemaException>("Integer 10 equals minimum value of 10 and exclusive minimum is true.", 273 () => 274 { 275 JsonSchema schema = new JsonSchema(); 276 schema.Minimum = 10; 277 schema.ExclusiveMinimum = true; 278 279 JValue v = new JValue(10); 280 v.Validate(schema); 281 }); 282 } 283 284 [Test] ExclusiveMinimum_Float()285 public void ExclusiveMinimum_Float() 286 { 287 ExceptionAssert.Throws<JsonSchemaException>("Float 10.1 equals minimum value of 10.1 and exclusive minimum is true.", 288 () => 289 { 290 JsonSchema schema = new JsonSchema(); 291 schema.Minimum = 10.1; 292 schema.ExclusiveMinimum = true; 293 294 JValue v = new JValue(10.1); 295 v.Validate(schema); 296 }); 297 } 298 299 [Test] DivisibleBy_Int()300 public void DivisibleBy_Int() 301 { 302 ExceptionAssert.Throws<JsonSchemaException>("Integer 10 is not evenly divisible by 3.", 303 () => 304 { 305 JsonSchema schema = new JsonSchema(); 306 schema.DivisibleBy = 3; 307 308 JValue v = new JValue(10); 309 v.Validate(schema); 310 }); 311 } 312 } 313 }