1 // 2 // System.Xml.XmlSchemaDatatypeTests.cs 3 // 4 // Author: 5 // Atsushi Enomoto <ginga@kit.hi-ho.ne.jp> 6 // Wojciech Kotlarski <wojciech.kotlarski@7digital.com> 7 // Andres G. Aragoneses <andres.aragoneses@7digital.com> 8 // 9 // (C) 2002 Atsushi Enomoto 10 // (C) 2012 7digital Media Ltd. 11 // 12 13 using System; 14 using System.IO; 15 using System.Xml; 16 using System.Xml.Schema; 17 using System.Collections.Generic; 18 using NUnit.Framework; 19 20 using QName = System.Xml.XmlQualifiedName; 21 using SimpleType = System.Xml.Schema.XmlSchemaSimpleType; 22 using SimpleRest = System.Xml.Schema.XmlSchemaSimpleTypeRestriction; 23 using AssertType = NUnit.Framework.Assert; 24 25 namespace MonoTests.System.Xml 26 { 27 [TestFixture] 28 public class XmlSchemaDatatypeTests 29 { GetSchema(string path)30 private XmlSchema GetSchema (string path) 31 { 32 return XmlSchema.Read (new XmlTextReader (path), null); 33 } 34 QName(string name, string ns)35 private XmlQualifiedName QName (string name, string ns) 36 { 37 return new XmlQualifiedName (name, ns); 38 } 39 AssertDatatype(XmlSchema schema, int index, XmlTokenizedType tokenizedType, Type type, string rawValue, object parsedValue)40 private void AssertDatatype (XmlSchema schema, int index, 41 XmlTokenizedType tokenizedType, Type type, string rawValue, object parsedValue) 42 { 43 XmlSchemaElement element = schema.Items [index] as XmlSchemaElement; 44 XmlSchemaDatatype dataType = element.ElementType as XmlSchemaDatatype; 45 Assert.AreEqual (tokenizedType, dataType.TokenizedType, "#1"); 46 Assert.AreEqual (type, dataType.ValueType, "#2"); 47 Assert.AreEqual (parsedValue, dataType.ParseValue (rawValue, null, null), "#3"); 48 } 49 50 [Test] 51 [Ignore ("The behavior has been inconsistent between versions, so it is not worthy of testing.")] 52 // Note that it could also apply to BaseTypeName (since if 53 // it is xs:anyType and BaseType is empty, BaseTypeName 54 // should be xs:anyType). TestAnyType()55 public void TestAnyType () 56 { 57 XmlSchema schema = GetSchema ("Test/XmlFiles/xsd/datatypesTest.xsd"); 58 schema.Compile (null); 59 XmlSchemaElement any = schema.Elements [QName ("e00", "urn:bar")] as XmlSchemaElement; 60 XmlSchemaComplexType cType = any.ElementType as XmlSchemaComplexType; 61 Assert.AreEqual (typeof (XmlSchemaComplexType), cType.GetType (), "#1"); 62 Assert.IsNotNull (cType, "#2"); 63 Assert.AreEqual (XmlQualifiedName.Empty, cType.QualifiedName, "#3"); 64 Assert.IsNull (cType.BaseSchemaType, "#4"); // In MS.NET 2.0 its null. In 1.1 it is not null. 65 Assert.IsNotNull (cType.ContentTypeParticle, "#5"); 66 } 67 68 [Test] TestAll()69 public void TestAll () 70 { 71 XmlSchema schema = GetSchema ("Test/XmlFiles/xsd/datatypesTest.xsd"); 72 schema.Compile (null); 73 74 AssertDatatype (schema, 1, XmlTokenizedType.CDATA, typeof (string), " f o o ", " f o o "); 75 AssertDatatype (schema, 2, XmlTokenizedType.CDATA, typeof (string), " f o o ", " f o o "); 76 // token shouldn't allow " f o o " 77 AssertDatatype (schema, 3, XmlTokenizedType.CDATA, typeof (string), "f o o", "f o o"); 78 // language seems to be checked strictly 79 AssertDatatype (schema, 4, XmlTokenizedType.CDATA, typeof (string), "x-foo", "x-foo"); 80 81 // NMTOKEN shouldn't allow " f o o " 82 // AssertDatatype (schema, 5, XmlTokenizedType.NMTOKEN, typeof (string), "foo", "foo"); 83 // AssertDatatype (schema, 6, XmlTokenizedType.NMTOKEN, typeof (string []), "f o o", new string [] {"f", "o", "o"}); 84 } 85 86 [Test] AnyUriRelativePath()87 public void AnyUriRelativePath () 88 { 89 XmlValidatingReader vr = new XmlValidatingReader ( 90 new XmlTextReader ( 91 // relative path value that contains ':' should be still valid. 92 "<root>../copy/myserver/</root>", 93 XmlNodeType.Document, null)); 94 vr.Schemas.Add (XmlSchema.Read ( 95 new XmlTextReader ("<xs:schema xmlns:xs='" 96 + XmlSchema.Namespace + 97 "'><xs:element name='root' type='xs:anyURI' /></xs:schema>", 98 XmlNodeType.Document, null), null)); 99 vr.Read (); 100 vr.Read (); 101 vr.Read (); 102 } 103 104 [Test] AnyUriRelativePathContainsColon()105 public void AnyUriRelativePathContainsColon () 106 { 107 XmlValidatingReader vr = new XmlValidatingReader ( 108 new XmlTextReader ( 109 // relative path value that contains ':' should be still valid. 110 "<root>../copy/myserver/c:/foo</root>", 111 XmlNodeType.Document, null)); 112 vr.Schemas.Add (XmlSchema.Read ( 113 new XmlTextReader ("<xs:schema xmlns:xs='" 114 + XmlSchema.Namespace + 115 "'><xs:element name='root' type='xs:anyURI' /></xs:schema>", 116 XmlNodeType.Document, null), null)); 117 vr.Read (); 118 vr.Read (); 119 vr.Read (); 120 } 121 122 string [] allTypes = new string [] { 123 "string", "boolean", "float", "double", "decimal", 124 "duration", "dateTime", "time", "date", "gYearMonth", 125 "gYear", "gMonthDay", "gDay", "gMonth", "hexBinary", 126 "base64Binary", "anyURI", "QName", "NOTATION", 127 "normalizedString", "token", "language", "IDREFS", 128 "ENTITIES", "NMTOKEN", "NMTOKENS", "Name", "NCName", 129 "ID", "IDREF", "ENTITY", "integer", 130 "nonPositiveInteger", "negativeInteger", "long", 131 "int", "short", "byte", "nonNegativeInteger", 132 "unsignedLong", "unsignedInt", "unsignedShort", 133 "unsignedByte", "positiveInteger" 134 }; 135 136 XmlSchemaSet allWrappers; 137 SetupSimpleTypeWrappers()138 void SetupSimpleTypeWrappers () 139 { 140 XmlSchema schema = new XmlSchema (); 141 List<QName> qnames = new List<QName> (); 142 foreach (string name in allTypes) { 143 SimpleType st = new SimpleType (); 144 st.Name = "x-" + name; 145 SimpleRest r = new SimpleRest (); 146 st.Content = r; 147 QName qname = new QName (name, XmlSchema.Namespace); 148 r.BaseTypeName = qname; 149 qnames.Add (qname); 150 schema.Items.Add (st); 151 } 152 XmlSchemaSet sset = new XmlSchemaSet (); 153 sset.Add (schema); 154 sset.Compile (); 155 allWrappers = sset; 156 } 157 GetDatatype(string name)158 XmlSchemaDatatype GetDatatype (string name) 159 { 160 return (allWrappers.GlobalTypes [new QName ("x-" + name, 161 String.Empty)] as SimpleType).Datatype; 162 } 163 GetDerived(string target)164 string [] GetDerived (string target) 165 { 166 XmlSchemaDatatype strType = GetDatatype (target); 167 List<string> results = new List<string> (); 168 foreach (string name in allTypes) { 169 if (name == target) 170 continue; 171 XmlSchemaDatatype deriv = GetDatatype (name); 172 if (deriv.IsDerivedFrom (strType)) 173 results.Add (name); 174 else Console.Error.WriteLine (deriv.GetType () + " is not derived from " + strType.GetType ()); 175 } 176 return results.ToArray (); 177 } 178 179 [Test] IsDerivedFrom()180 public void IsDerivedFrom () 181 { 182 SetupSimpleTypeWrappers (); 183 184 // Funky, but XmlSchemaDatatype.IsDerivedFrom() is 185 // documented to always return false, but actually 186 // matches the same type - which could be guessed that 187 // this method is used only to detect user-defined 188 // simpleType derivation. 189 foreach (string b in allTypes) 190 foreach (string d in allTypes) 191 AssertType.AreEqual (b == d, GetDatatype (d).IsDerivedFrom (GetDatatype (b)), b); 192 193 AssertType.IsFalse (GetDatatype ("string").IsDerivedFrom (null), "null arg"); 194 } 195 196 [Test] ChangeType_StringTest()197 public void ChangeType_StringTest() 198 { 199 XmlSchemaDatatype datatype = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String).Datatype; 200 Assert.IsTrue (datatype != null); 201 Assert.AreEqual (XmlTypeCode.String, datatype.TypeCode); 202 Assert.AreEqual (typeof(string), datatype.ValueType); 203 204 Assert.AreEqual ("test", datatype.ChangeType("test", typeof(string))); 205 } 206 207 [Test] ChangeType_StringToObjectTest()208 public void ChangeType_StringToObjectTest() 209 { 210 XmlSchemaDatatype datatype = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String).Datatype; 211 Assert.IsTrue (datatype != null); 212 Assert.AreEqual (XmlTypeCode.String, datatype.TypeCode); 213 Assert.AreEqual (typeof(string), datatype.ValueType); 214 215 Assert.AreEqual ("test", datatype.ChangeType("test", typeof(object))); 216 } 217 218 [Test] ChangeType_IntegerTest()219 public void ChangeType_IntegerTest() 220 { 221 XmlSchemaDatatype datatype = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Integer).Datatype; 222 Assert.IsTrue (datatype != null); 223 Assert.AreEqual (XmlTypeCode.Integer, datatype.TypeCode); 224 Assert.AreEqual (typeof(decimal), datatype.ValueType); 225 226 Assert.AreEqual (300, datatype.ChangeType("300", typeof(int))); 227 } 228 229 [Test] ChangeType_FromDateTimeTest()230 public void ChangeType_FromDateTimeTest() 231 { 232 XmlSchemaDatatype datatype = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.DateTime).Datatype; 233 Assert.IsTrue (datatype != null); 234 Assert.AreEqual (XmlTypeCode.DateTime, datatype.TypeCode); 235 Assert.AreEqual (typeof(DateTime), datatype.ValueType); 236 237 DateTime date = new DateTime (2012, 06, 27, 0, 0, 0, DateTimeKind.Utc); 238 Assert.AreEqual ("2012-06-27T00:00:00Z", datatype.ChangeType(date, typeof(string))); 239 } 240 241 [Test] ChangeType_FromTimeSpanTest()242 public void ChangeType_FromTimeSpanTest() 243 { 244 XmlSchemaDatatype datatype = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.DayTimeDuration).Datatype; 245 Assert.IsTrue (datatype != null); 246 Assert.AreEqual (XmlTypeCode.DayTimeDuration, datatype.TypeCode); 247 Assert.AreEqual (typeof(TimeSpan), datatype.ValueType); 248 249 TimeSpan span = new TimeSpan(1, 2, 3); 250 Assert.AreEqual ("PT1H2M3S", datatype.ChangeType(span, typeof(string))); 251 } 252 253 [Test] ChangeType_ToDateTimeTest()254 public void ChangeType_ToDateTimeTest() 255 { 256 XmlSchemaDatatype datatype = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.DateTime).Datatype; 257 Assert.IsTrue (datatype != null); 258 Assert.AreEqual (XmlTypeCode.DateTime, datatype.TypeCode); 259 Assert.AreEqual (typeof(DateTime), datatype.ValueType); 260 261 DateTime date = new DateTime (2012, 06, 27, 0, 0, 0, DateTimeKind.Utc); 262 Assert.AreEqual (date, datatype.ChangeType("2012-06-27T00:00:00Z", typeof(DateTime))); 263 } 264 265 [Test] ChangeType_ToTimeSpanTest()266 public void ChangeType_ToTimeSpanTest() 267 { 268 XmlSchemaDatatype datatype = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.DayTimeDuration).Datatype; 269 Assert.IsTrue (datatype != null); 270 Assert.AreEqual (XmlTypeCode.DayTimeDuration, datatype.TypeCode); 271 Assert.AreEqual (typeof(TimeSpan), datatype.ValueType); 272 273 TimeSpan span = new TimeSpan(1, 2, 3); 274 Assert.AreEqual (span, datatype.ChangeType("PT1H2M3S", typeof(TimeSpan))); 275 } 276 277 [Test] 278 [ExpectedException(typeof(ArgumentNullException))] ChangeType_NullValueArgumentInFromStringTest()279 public void ChangeType_NullValueArgumentInFromStringTest() 280 { 281 XmlSchemaDatatype datatype = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Integer).Datatype; 282 datatype.ChangeType(null, typeof(string)); 283 } 284 285 [Test] 286 [ExpectedException(typeof(ArgumentNullException))] ChangeType_NullValueArgumentInToStringTest()287 public void ChangeType_NullValueArgumentInToStringTest() 288 { 289 XmlSchemaDatatype datatype = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Integer).Datatype; 290 datatype.ChangeType(null, typeof(int)); 291 } 292 293 [Test] 294 [ExpectedException(typeof(ArgumentNullException))] ChangeType_NullTargetArgumentInFromStringTest()295 public void ChangeType_NullTargetArgumentInFromStringTest() 296 { 297 XmlSchemaDatatype datatype = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Integer).Datatype; 298 datatype.ChangeType("100", null); 299 } 300 301 [Test] 302 [ExpectedException(typeof(ArgumentNullException))] ChangeType_NullNamespaceResolverArgumentInFromStringTest()303 public void ChangeType_NullNamespaceResolverArgumentInFromStringTest() 304 { 305 XmlSchemaDatatype datatype = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Integer).Datatype; 306 datatype.ChangeType("100", typeof(string), null); 307 } 308 309 [Test] 310 [Category("NotWorking")] 311 [ExpectedException (typeof(InvalidCastException))] InvalidCastExceptionTest()312 public void InvalidCastExceptionTest() 313 { 314 XmlSchemaDatatype datatype = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.DateTime).Datatype; 315 Assert.IsTrue (datatype != null); 316 Assert.AreEqual (XmlTypeCode.DateTime, datatype.TypeCode); 317 Assert.AreEqual (typeof(DateTime), datatype.ValueType); 318 319 datatype.ChangeType(300, typeof (int)); 320 } 321 322 [Test] Bug12469()323 public void Bug12469 () 324 { 325 Dictionary<string, string> validValues = new Dictionary<string, string> { 326 {"string", "abc"}, 327 328 {"normalizedString", "abc"}, 329 {"token", "abc"}, 330 {"language", "en"}, 331 {"Name", "abc"}, 332 {"NCName", "abc"}, 333 {"ID", "abc"}, 334 {"ENTITY", "abc"}, 335 {"NMTOKEN", "abc"}, 336 337 {"boolean", "true"}, 338 {"decimal", "1"}, 339 {"integer", "1"}, 340 {"nonPositiveInteger", "0"}, 341 {"negativeInteger", "-1"}, 342 {"long", "9223372036854775807"}, 343 {"int", "2147483647"}, 344 {"short", "32767"}, 345 {"byte", "127"}, 346 {"nonNegativeInteger", "0"}, 347 {"unsignedLong", "18446744073709551615"}, 348 {"unsignedInt", "4294967295"}, 349 {"unsignedShort", "65535"}, 350 {"unsignedByte", "255"}, 351 {"positiveInteger", "1"}, 352 {"float", "1.1"}, 353 {"double", "1.1"}, 354 {"time", "00:00:00"}, 355 {"date", "1999-12-31"}, 356 {"dateTime", "1999-12-31T00:00:00.000"}, 357 {"duration", "P1Y2M3DT10H30M"}, 358 {"gYearMonth", "1999-01"}, 359 {"gYear", "1999"}, 360 {"gMonthDay", "--12-31"}, 361 {"gMonth", "--12"}, 362 {"gDay", "---31"}, 363 364 {"base64Binary", "AbCd eFgH IjKl 019+"}, 365 {"hexBinary", "0123456789ABCDEF"}, 366 367 {"anyURI", "https://www.server.com"}, 368 {"QName", "xml:abc"}, 369 }; 370 371 // FIXME: implement validation 372 Dictionary<string, string> invalidValues = new Dictionary<string, string> { 373 {"Name", "***"}, 374 {"NCName", "a::"}, 375 {"ID", "123"}, 376 {"ENTITY", "***"}, 377 {"NMTOKEN", "***"}, 378 379 {"boolean", "ABC"}, 380 {"decimal", "1A"}, 381 {"integer", "1.5"}, 382 {"nonPositiveInteger", "5"}, 383 {"negativeInteger", "10"}, 384 {"long", "999999999999999999999999999999999999999"}, 385 {"int", "999999999999999999999999999999999999999"}, 386 {"short", "32768"}, 387 {"byte", "128"}, 388 {"nonNegativeInteger", "-1"}, 389 {"unsignedLong", "-1"}, 390 {"unsignedInt", "-1"}, 391 {"unsignedShort", "-1"}, 392 {"unsignedByte", "-1"}, 393 {"positiveInteger", "0"}, 394 {"float", "1.1x"}, 395 {"double", "1.1x"}, 396 {"time", "0"}, 397 {"date", "1"}, 398 {"dateTime", "2"}, 399 {"duration", "P1"}, 400 {"gYearMonth", "1999"}, 401 {"gYear", "-1"}, 402 {"gMonthDay", "-12-31"}, 403 {"gMonth", "-12"}, 404 {"gDay", "--31"}, 405 406 {"base64Binary", "####"}, 407 {"hexBinary", "G"}, 408 409 // anyURI passes everything (as long as I observed) 410 {"QName", "::"}, 411 }; 412 413 const string schemaTemplate = @" 414 <xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema' elementFormDefault='qualified'> 415 <xs:element name='EL'> 416 <xs:complexType> 417 <xs:attribute name='attr' type='xs:{0}' use='required' /> 418 </xs:complexType> 419 </xs:element> 420 </xs:schema>"; 421 422 const string documentTemplate = @"<EL attr='{0}' />"; 423 424 foreach (var type in validValues.Keys) { 425 try { 426 var schema = string.Format (schemaTemplate, type); 427 var document = string.Format (documentTemplate, validValues[type]); 428 429 var schemaSet = new XmlSchemaSet (); 430 using (var reader = new StringReader (schema)) 431 schemaSet.Add (XmlSchema.Read (reader, null)); 432 schemaSet.Compile (); 433 var doc = new XmlDocument (); 434 using (var reader = new StringReader (document)) 435 doc.Load (reader); 436 doc.Schemas = schemaSet; 437 doc.Validate (null); 438 439 // FIXME: implement validation 440 /* 441 if (!invalidValues.ContainsKey (type)) 442 continue; 443 try { 444 doc = new XmlDocument (); 445 document = string.Format (documentTemplate, invalidValues [type]); 446 using (var reader = new StringReader (document)) 447 doc.Load (reader); 448 doc.Schemas = schemaSet; 449 doc.Validate (null); 450 Assert.Fail (string.Format ("Failed to invalidate {0} for {1}", document, type)); 451 } catch (XmlSchemaException) { 452 } 453 */ 454 } catch (Exception) { 455 Console.Error.WriteLine (type); 456 throw; 457 } 458 } 459 } 460 } 461 } 462