context: //
  // Authors:
  //   Atsushi Enomoto
  //
  // Copyright 2007 Novell (http://www.novell.com)
  //
  // Permission is hereby granted, free of charge, to any person obtaining
  // a copy of this software and associated documentation files (the
  // "Software"), to deal in the Software without restriction, including
  // without limitation the rights to use, copy, modify, merge, publish,
  // distribute, sublicense, and/or sell copies of the Software, and to
  // permit persons to whom the Software is furnished to do so, subject to
  // the following conditions:
  // 
  // The above copyright notice and this permission notice shall be
  // included in all copies or substantial portions of the Software.
  // 
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  //
  
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Xml;
  using System.Xml.Linq;
  
  using NUnit.Framework;
  
  namespace MonoTests.System.Xml.Linq
  {
  	[TestFixture]
  	public class XAttributeTest
  	{
  		[Test]
  		public void Annotations_GetSubclass()
  		{
  			var x = new XAttribute("foo", "bar");
  			var annotation = new InvalidCastException();
  			x.AddAnnotation(annotation);
  			
  			Assert.AreSame(annotation, x.Annotation<InvalidCastException>(), "#1");
  			Assert.AreSame(annotation, x.Annotation<object>(), "#2");
  			Assert.AreSame(annotation, x.Annotations<object>().Single (), "#3");
  		}
  
  		[Test]
  		public void Annotations_SameTypeTwice()
  		{
  			var x = new XAttribute("foo", "bar");
  			var first = new InvalidCastException();
  			var second = new InvalidCastException();
  			x.AddAnnotation(first);
  			x.AddAnnotation(second);
  			Assert.AreEqual(2, x.Annotations<object>().Count(), "#1");
  			Assert.AreSame(first, x.Annotation<object>(), "#2");
  		}
  
  		[Test]
  		public void Constructor_NullParameters ()
  		{
  			AssertThrows<ArgumentNullException>(() => new XAttribute(null, "v"), "#1");
  			AssertThrows<ArgumentNullException>(() => new XAttribute(XName.Get("a"), null), "#2");
  			AssertThrows<ArgumentNullException>(() => new XAttribute((XAttribute) null), "#3");
  		}
  
  		[Test]
  		public void IsNamespaceDeclaration ()
  		{
  			string xml = "<root a='v' xmlns='urn:foo' xmlns:x='urn:x' x:a='v' xmlns:xml='http://www.w3.org/XML/1998/namespace' />";
  			XElement el = XElement.Parse (xml);
  			List<XAttribute> l = new List<XAttribute> (el.Attributes ());
  			Assert.IsFalse (l [0].IsNamespaceDeclaration, "#1");
  			Assert.IsTrue (l [1].IsNamespaceDeclaration, "#2");
  			Assert.IsTrue (l [2].IsNamespaceDeclaration, "#3");
  			Assert.IsFalse (l [3].IsNamespaceDeclaration, "#4");
  			Assert.IsTrue (l [4].IsNamespaceDeclaration, "#5");
  
  			Assert.AreEqual ("a", l [0].Name.LocalName, "#2-1");
  			Assert.AreEqual ("xmlns", l [1].Name.LocalName, "#2-2");
  			Assert.AreEqual ("x", l [2].Name.LocalName, "#2-3");
  			Assert.AreEqual ("a", l [3].Name.LocalName, "#2-4");
  			Assert.AreEqual ("xml", l [4].Name.LocalName, "#2-5");
  
  			Assert.AreEqual ("", l [0].Name.NamespaceName, "#3-1");
  			// not sure how current Orcas behavior makes sense here though ...
  			Assert.AreEqual ("", l [1].Name.NamespaceName, "#3-2");
  			Assert.AreEqual ("http://www.w3.org/2000/xmlns/", l [2].Name.NamespaceName, "#3-3");
  			Assert.AreEqual ("urn:x", l [3].Name.NamespaceName, "#3-4");
  			Assert.AreEqual ("http://www.w3.org/2000/xmlns/", l [4].Name.NamespaceName, "#3-5");
  		}
  
  		[Test]
  		public void Document ()
  		{
  			XDocument doc = XDocument.Parse ("<root a='v' />");
  			Assert.AreEqual (doc, doc.Root.Document, "#1");
  			foreach (XAttribute a in doc.Root.Attributes ())
  				Assert.AreEqual (doc, a.Document, "#2");
  			Assert.AreEqual (doc, doc.Document, "#3");
  		}
  
  		[Test]
  		public void SetValue ()
  		{
  			XAttribute a = new XAttribute (XName.Get ("a"), "v");
  			a.SetValue (new XDeclaration ("1.0", null, null));
  			// value object is converted to a string.
  			Assert.AreEqual ("<?xml version=\"1.0\"?>", a.Value, "#1");
  		}
  
  		[Test]
  		public void SetValue_Null()
  		{
  			var a = new XAttribute("foo", "bar");
  			AssertThrows<ArgumentNullException>(() => a.Value = null, "#1");
  			AssertThrows<ArgumentNullException>(() => a.SetValue (null), "#2");
  		}
  
  		[Test]
  		public void SetValue_ChangeTriggers()
  		{
  			bool changing = false;
  			bool changed = false;
  
  			var a = new XAttribute("foo", "bar");
  			a.Changing += (o, e) => {
  				Assert.IsFalse(changing, "#1");
  				Assert.IsFalse(changed, "#2");
  				Assert.AreSame(a, o, "#3");
  				Assert.AreEqual(XObjectChange.Value, e.ObjectChange, "#4");
  				changing = true;
  			};
  			a.Changed += (o, e) => {
  				Assert.IsTrue(changing, "#5");
  				Assert.IsFalse(changed, "#6");
  				Assert.AreSame(a, o, "#7");
  				Assert.AreEqual(XObjectChange.Value, e.ObjectChange, "#8");
  				changed = true;
  			};
  			a.Value = "foo";
  			Assert.IsTrue(changing, "changing");
  			Assert.IsTrue(changed, "changed");
  		}
  
  		[Test]
  		public void SetValue2_ChangeTriggers()
  		{
  			bool changing = false;
  			bool changed = false;
  			
  			var a = new XAttribute("foo", "bar");
  			a.Changing += (o, e) =>
  			{
  				Assert.IsFalse(changing, "#1");
  				Assert.IsFalse(changed, "#2");
  				Assert.AreSame(a, o, "#3");
  				Assert.AreEqual(XObjectChange.Value, e.ObjectChange, "#4");
  				changing = true;
  			};
  			a.Changed += (o, e) =>
  			{
  				Assert.IsTrue(changing, "#5");
  				Assert.IsFalse(changed, "#6");
  				Assert.AreSame(a, o, "#7");
  				Assert.AreEqual(XObjectChange.Value, e.ObjectChange, "#8");
  				changed = true;
  			};
  			a.SetValue("zap");
  			Assert.IsTrue(changing, "changing");
  			Assert.IsTrue(changed, "changed");
  		}
  
  		[Test]
  		public void SetValue_SameValue_ChangeTrigger()
  		{
  			int changed = 0;
  			int changing = 0;
  
  			var a = new XAttribute("foo", "bar");
  			a.Changed += (o, e) => changed++;
  			a.Changing += (o, e) => changing++;
  
  			a.SetValue("bar");
  			Assert.AreEqual(1, changed, "#1");
  			Assert.AreEqual(1, changing, "#2");
  
  			a.Value = "bar";
  			Assert.AreEqual(2, changed, "#3");
  			Assert.AreEqual(2, changing, "#4");
  		}
  
  		[Test]
  		public void ToString ()
  		{
  			XAttribute a = new XAttribute (XName.Get ("a"), "v");
  			Assert.AreEqual ("a=\"v\"", a.ToString ());
  
  			a = new XAttribute (XName.Get ("a"), " >_< ");
  			Assert.AreEqual ("a=\" &gt;_&lt; \"", a.ToString ());
  		}
  
  		[Test]
  		public void ToString_Xamarin29935 ()
  		{
  			var doc = XDocument.Parse ("<?xml version='1.0' encoding='utf-8'?><lift xmlns:test='http://test.example.com'></lift>");
  			Assert.AreEqual ("xmlns:test=\"http://test.example.com\"",
  				doc.Root.Attributes ().Select (s => s.ToString ()).First ());
  		}
  
  		[Test]
  		public void DateTimeAttribute ()
  		{
  			var date = DateTime.Now;
  			var attribute = new XAttribute ("Date", date);
  
  			var value = (DateTime) attribute;
  
  			Assert.AreEqual (date, value);
  		}
  
  #pragma warning disable 219
  		[Test]
  		public void CastNulls ()
  		{
  			const XAttribute a = null;
  
  			Assert.AreEqual (null, (bool?) a, "bool?");
  			Assert.AreEqual (null, (DateTime?) a, "DateTime?");
  			Assert.AreEqual (null, (DateTimeOffset?) a, "DateTimeOffset?");
  			Assert.AreEqual (null, (decimal?) a, "decimal?");
  			Assert.AreEqual (null, (double?) a, "double?");
  			Assert.AreEqual (null, (float?) a, "float?");
  			Assert.AreEqual (null, (Guid?) a, "Guid?");
  			Assert.AreEqual (null, (int?) a, "int?");
  			Assert.AreEqual (null, (long?) a, "long?");
  			Assert.AreEqual (null, (uint?) a, "uint?");
  			Assert.AreEqual (null, (ulong?) a, "ulong?");
  			Assert.AreEqual (null, (TimeSpan?) a, "TimeSpan?");
  			Assert.AreEqual (null, (string) a, "string");
  			AssertThrows<ArgumentNullException> (() => { bool z = (bool) a; }, "bool");
  			AssertThrows<ArgumentNullException> (() => { DateTime z = (DateTime) a; }, "DateTime");
  			AssertThrows<ArgumentNullException> (() => { DateTimeOffset z = (DateTimeOffset) a; }, "DateTimeOffset");
  			AssertThrows<ArgumentNullException> (() => { decimal z = (decimal) a; }, "decimal");
  			AssertThrows<ArgumentNullException> (() => { double z = (double) a; }, "double");
  			AssertThrows<ArgumentNullException> (() => { float z = (float) a; }, "float");
  			AssertThrows<ArgumentNullException> (() => { Guid z = (Guid) a; }, "Guid");
  			AssertThrows<ArgumentNullException> (() => { int z = (int) a; }, "int");
  			AssertThrows<ArgumentNullException> (() => { long z = (long) a; }, "long");
  			AssertThrows<ArgumentNullException> (() => { uint z = (uint) a; }, "uint");
  			AssertThrows<ArgumentNullException> (() => { ulong z = (ulong) a; }, "ulong");
  			AssertThrows<ArgumentNullException> (() => { TimeSpan z = (TimeSpan) a; }, "TimeSpan");
  		}
  
  		/// <remarks>
  		/// Provides functionality similar to Assert.Throws that is available on newer versions of NUnit.
  		/// </remarks>
  		private static T AssertThrows<T> (Action code, string message, params object[] args) where T : Exception
  		{
  			Exception actual = null;
  			try {
  				code ();
  			} catch (Exception exception) {
  				actual = exception;
  			}
  			Assert.That (actual, new NUnit.Framework.Constraints.ExactTypeConstraint (typeof (T)), message, args);
  			return (T) actual;
  		}
  
  		[Test]
  		public void CastEmptiesOrBlanks ()
  		{
  			XAttribute a = new XAttribute ("a", String.Empty);
  
  			// Verify expected "cloning" and "empty/blank" behaviour as prerequisites
  			Assert.AreEqual (String.Empty, a.Value, "#1-1");
  			Assert.AreEqual (String.Empty, new XAttribute (a).Value, "#1-2");
  			Assert.AreNotSame (a, new XAttribute (a), "#2-1");
  			Assert.AreEqual (a.ToString (), new XAttribute (a).ToString (), "#2-2");
  			Assert.AreEqual ("a=\"\"", a.ToString (), "#2-3");
  
  			// Execute the primary assertions of this test
  			AssertThrows<FormatException> (() => { bool? z = (bool?) new XAttribute (a); }, "bool?");
  			AssertThrows<FormatException> (() => { DateTime? z = (DateTime?) new XAttribute (a); }, "DateTime?");
  			AssertThrows<FormatException> (() => { DateTimeOffset? z = (DateTimeOffset?) new XAttribute (a); }, "DateTimeOffset?");
  			AssertThrows<FormatException> (() => { decimal? z = (decimal?) new XAttribute (a); }, "decimal?");
  			AssertThrows<FormatException> (() => { double? z = (double?) new XAttribute (a); }, "double?");
  			AssertThrows<FormatException> (() => { float? z = (float?) new XAttribute (a); }, "float?");
  			AssertThrows<FormatException> (() => { Guid? z = (Guid?) new XAttribute (a); }, "Guid?");
  			AssertThrows<FormatException> (() => { int? z = (int?) new XAttribute (a); }, "int?");
  			AssertThrows<FormatException> (() => { long? z = (long?) new XAttribute (a); }, "long?");
  			AssertThrows<FormatException> (() => { uint? z = (uint?) new XAttribute (a); }, "uint?");
  			AssertThrows<FormatException> (() => { ulong? z = (ulong?) new XAttribute (a); }, "ulong?");
  			AssertThrows<FormatException> (() => { TimeSpan? z = (TimeSpan?) new XAttribute (a); }, "TimeSpan?");
  			Assert.AreEqual (String.Empty, (string) new XAttribute (a), "string");
  			AssertThrows<FormatException> (() => { bool z = (bool) new XAttribute (a); }, "bool");
  			AssertThrows<FormatException> (() => { DateTime z = (DateTime) new XAttribute (a); }, "DateTime");
  			AssertThrows<FormatException> (() => { DateTimeOffset z = (DateTimeOffset) new XAttribute (a); }, "DateTimeOffset");
  			AssertThrows<FormatException> (() => { decimal z = (decimal) new XAttribute (a); }, "decimal");
  			AssertThrows<FormatException> (() => { double z = (double) new XAttribute (a); }, "double");
  			AssertThrows<FormatException> (() => { float z = (float) new XAttribute (a); }, "float");
  			AssertThrows<FormatException> (() => { Guid z = (Guid) new XAttribute (a); }, "Guid");
  			AssertThrows<FormatException> (() => { int z = (int) new XAttribute (a); }, "int");
  			AssertThrows<FormatException> (() => { long z = (long) new XAttribute (a); }, "long");
  			AssertThrows<FormatException> (() => { uint z = (uint) new XAttribute (a); }, "uint");
  			AssertThrows<FormatException> (() => { ulong z = (ulong) new XAttribute (a); }, "ulong");
  			AssertThrows<FormatException> (() => { TimeSpan z = (TimeSpan) new XAttribute (a); }, "TimeSpan");
  		}
  
  		[Test]
  		public void CastSpaces ()
  		{
  			XAttribute a = new XAttribute ("a", " ");
  
  			// Verify expected "cloning" and "space" behaviour as prerequisites
  			Assert.AreEqual (" ", a.Value, "#1-1");
  			Assert.AreEqual (" ", new XAttribute (a).Value, "#1-2");
  			Assert.AreNotSame (a, new XAttribute (a), "#2-1");
  			Assert.AreEqual (a.ToString (), new XAttribute (a).ToString (), "#2-2");
  			Assert.AreEqual ("a=\" \"", a.ToString (), "#2-3");
  			Assert.AreEqual (a.ToString (), new XAttribute ("a", ' ').ToString (), "#2-4");
  
  			// Execute the primary assertions of this test
  			AssertThrows<FormatException> (() => { bool? z = (bool?) new XAttribute (a); }, "bool?");
  			AssertThrows<FormatException> (() => { DateTime? z = (DateTime?) new XAttribute (a); }, "DateTime?");
  			AssertThrows<FormatException> (() => { DateTimeOffset? z = (DateTimeOffset?) new XAttribute (a); }, "DateTimeOffset?");
  			AssertThrows<FormatException> (() => { decimal? z = (decimal?) new XAttribute (a); }, "decimal?");
  			AssertThrows<FormatException> (() => { double? z = (double?) new XAttribute (a); }, "double?");
  			AssertThrows<FormatException> (() => { float? z = (float?) new XAttribute (a); }, "float?");
  			AssertThrows<FormatException> (() => { Guid? z = (Guid?) new XAttribute (a); }, "Guid?");
  			AssertThrows<FormatException> (() => { int? z = (int?) new XAttribute (a); }, "int?");
  			AssertThrows<FormatException> (() => { long? z = (long?) new XAttribute (a); }, "long?");
  			AssertThrows<FormatException> (() => { uint? z = (uint?) new XAttribute (a); }, "uint?");
  			AssertThrows<FormatException> (() => { ulong? z = (ulong?) new XAttribute (a); }, "ulong?");
  			AssertThrows<FormatException> (() => { TimeSpan? z = (TimeSpan?) new XAttribute (a); }, "TimeSpan?");
  			Assert.AreEqual (" ", (string) new XAttribute (a), "string");
  			AssertThrows<FormatException> (() => { bool z = (bool) new XAttribute (a); }, "bool");
  			AssertThrows<FormatException> (() => { DateTime z = (DateTime) new XAttribute (a); }, "DateTime");
  			AssertThrows<FormatException> (() => { DateTimeOffset z = (DateTimeOffset) new XAttribute (a); }, "DateTimeOffset");
  			AssertThrows<FormatException> (() => { decimal z = (decimal) new XAttribute (a); }, "decimal");
  			AssertThrows<FormatException> (() => { double z = (double) new XAttribute (a); }, "double");
  			AssertThrows<FormatException> (() => { float z = (float) new XAttribute (a); }, "float");
  			AssertThrows<FormatException> (() => { Guid z = (Guid) new XAttribute (a); }, "Guid");
  			AssertThrows<FormatException> (() => { int z = (int) new XAttribute (a); }, "int");
  			AssertThrows<FormatException> (() => { long z = (long) new XAttribute (a); }, "long");
  			AssertThrows<FormatException> (() => { uint z = (uint) new XAttribute (a); }, "uint");
  			AssertThrows<FormatException> (() => { ulong z = (ulong) new XAttribute (a); }, "ulong");
  			AssertThrows<FormatException> (() => { TimeSpan z = (TimeSpan) new XAttribute (a); }, "TimeSpan");
  		}
  
  		[Test]
  		public void CastNumbers ()
  		{
  			XAttribute a = new XAttribute ("a", "7");
  			XAttribute b = new XAttribute ("b", "  42 ");
  
gt: 			XAttribute c = new XAttribute ("c", " \n\r   123 \t  ");