context: using NUnit.Framework;
  using TagLib;
  using TagLib.IFD;
  using TagLib.IFD.Entries;
  using TagLib.IFD.Tags;
  using TagLib.Xmp;
  using TaglibSharp.Tests.Images.Validators;
  
  namespace TaglibSharp.Tests.Images
  {
  	[TestFixture]
  	public class JpegNikon2Bibble5Test
  	{
  		[Test]
  		public void Test ()
  		{
  			ImageTest.Run ("sample_nikon2_bibble5.jpg",
  				new JpegNikon2Bibble5TestInvariantValidator (),
  				NoModificationValidator.Instance,
  				new CommentModificationValidator (string.Empty),
  				new TagCommentModificationValidator (null, TagTypes.TiffIFD, true),
  				new TagCommentModificationValidator (null, TagTypes.XMP, true),
  				new TagKeywordsModificationValidator (new string[] { }, TagTypes.XMP, true)
  			);
  		}
  	}
  
  	public class JpegNikon2Bibble5TestInvariantValidator : IMetadataInvariantValidator
  	{
  		public void ValidateMetadataInvariants (TagLib.Image.File file)
  		{
  			Assert.IsNotNull (file);
  			//  ---------- Start of IFD tests ----------
  
  			var tag = file.GetTag (TagTypes.TiffIFD) as IFDTag;
  			Assert.IsNotNull (tag, "IFD tag not found");
  
  			var structure = tag.Structure;
  
  			// Image.0x010F (Make/Ascii/18) "NIKON CORPORATION"
  			{
  				var entry = structure.GetEntry (0, (ushort)IFDEntryTag.Make);
  				Assert.IsNotNull (entry, "Entry 0x010F missing in IFD 0");
  				Assert.IsNotNull (entry as StringIFDEntry, "Entry is not a string!");
  				Assert.AreEqual ("NIKON CORPORATION", (entry as StringIFDEntry).Value);
  			}
  			// Image.0x0110 (Model/Ascii/10) "NIKON D90"
  			{
  				var entry = structure.GetEntry (0, (ushort)IFDEntryTag.Model);
  				Assert.IsNotNull (entry, "Entry 0x0110 missing in IFD 0");
  				Assert.IsNotNull (entry as StringIFDEntry, "Entry is not a string!");
  				Assert.AreEqual ("NIKON D90", (entry as StringIFDEntry).Value);
  			}
  			// Image.0x011A (XResolution/Rational/1) "150/1"
  			{
  				var entry = structure.GetEntry (0, (ushort)IFDEntryTag.XResolution);
  				Assert.IsNotNull (entry, "Entry 0x011A missing in IFD 0");
  				Assert.IsNotNull (entry as RationalIFDEntry, "Entry is not a rational!");
  				Assert.AreEqual (150, (entry as RationalIFDEntry).Value.Numerator);
  				Assert.AreEqual (1, (entry as RationalIFDEntry).Value.Denominator);
  			}
  			// Image.0x011B (YResolution/Rational/1) "150/1"
  			{
  				var entry = structure.GetEntry (0, (ushort)IFDEntryTag.YResolution);
  				Assert.IsNotNull (entry, "Entry 0x011B missing in IFD 0");
  				Assert.IsNotNull (entry as RationalIFDEntry, "Entry is not a rational!");
  				Assert.AreEqual (150, (entry as RationalIFDEntry).Value.Numerator);
  				Assert.AreEqual (1, (entry as RationalIFDEntry).Value.Denominator);
  			}
  			// Image.0x0128 (ResolutionUnit/Short/1) "2"
  			{
  				var entry = structure.GetEntry (0, (ushort)IFDEntryTag.ResolutionUnit);
  				Assert.IsNotNull (entry, "Entry 0x0128 missing in IFD 0");
  				Assert.IsNotNull (entry as ShortIFDEntry, "Entry is not a short!");
  				Assert.AreEqual (2, (entry as ShortIFDEntry).Value);
  			}
  			// Image.0x0131 (Software/Ascii/17) "Bibble 5 Pro 5.0"
  			{
  				var entry = structure.GetEntry (0, (ushort)IFDEntryTag.Software);
  				Assert.IsNotNull (entry, "Entry 0x0131 missing in IFD 0");
  				Assert.IsNotNull (entry as StringIFDEntry, "Entry is not a string!");
  				Assert.AreEqual ("Bibble 5 Pro 5.0", (entry as StringIFDEntry).Value);
  			}
  			// Image.0x8769 (ExifTag/SubIFD/1) "8"
  			{
  				var entry = structure.GetEntry (0, (ushort)IFDEntryTag.ExifIFD);
  				Assert.IsNotNull (entry, "Entry 0x8769 missing in IFD 0");
  				Assert.IsNotNull (entry as SubIFDEntry, "Entry is not a sub IFD!");
  			}
  
  			var exif = structure.GetEntry (0, (ushort)IFDEntryTag.ExifIFD) as SubIFDEntry;
  			Assert.IsNotNull (exif, "Exif tag not found");
  			var exif_structure = exif.Structure;
  
  			// Photo.0x010F (0x010f/Ascii/18) "NIKON CORPORATION"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)IFDEntryTag.Make);
  				Assert.IsNotNull (entry, "Entry 0x010F missing in IFD 0");
  				Assert.IsNotNull (entry as StringIFDEntry, "Entry is not a string!");
  				Assert.AreEqual ("NIKON CORPORATION", (entry as StringIFDEntry).Value);
  			}
  			// Photo.0x0110 (0x0110/Ascii/10) "NIKON D90"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)IFDEntryTag.Model);
  				Assert.IsNotNull (entry, "Entry 0x0110 missing in IFD 0");
  				Assert.IsNotNull (entry as StringIFDEntry, "Entry is not a string!");
  				Assert.AreEqual ("NIKON D90", (entry as StringIFDEntry).Value);
  			}
  			// Photo.0x0132 (0x0132/Ascii/20) "2010:02:03 10:51:31"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)IFDEntryTag.DateTime);
  				Assert.IsNotNull (entry, "Entry 0x0132 missing in IFD 0");
  				Assert.IsNotNull (entry as StringIFDEntry, "Entry is not a string!");
  				Assert.AreEqual ("2010:02:03 10:51:31", (entry as StringIFDEntry).Value);
  			}
  			// Photo.0x829A (ExposureTime/Rational/1) "10/600"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.ExposureTime);
  				Assert.IsNotNull (entry, "Entry 0x829A missing in IFD 0");
  				Assert.IsNotNull (entry as RationalIFDEntry, "Entry is not a rational!");
  				Assert.AreEqual (10, (entry as RationalIFDEntry).Value.Numerator);
  				Assert.AreEqual (600, (entry as RationalIFDEntry).Value.Denominator);
  			}
  			// Photo.0x829D (FNumber/Rational/1) "5557453/1048576"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.FNumber);
  				Assert.IsNotNull (entry, "Entry 0x829D missing in IFD 0");
  				Assert.IsNotNull (entry as RationalIFDEntry, "Entry is not a rational!");
  				Assert.AreEqual (5557453, (entry as RationalIFDEntry).Value.Numerator);
  				Assert.AreEqual (1048576, (entry as RationalIFDEntry).Value.Denominator);
  			}
  			// Photo.0x8822 (ExposureProgram/Short/1) "3"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.ExposureProgram);
  				Assert.IsNotNull (entry, "Entry 0x8822 missing in IFD 0");
  				Assert.IsNotNull (entry as ShortIFDEntry, "Entry is not a short!");
  				Assert.AreEqual (3, (entry as ShortIFDEntry).Value);
  			}
  			// Photo.0x8827 (ISOSpeedRatings/Short/1) "200"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.ISOSpeedRatings);
  				Assert.IsNotNull (entry, "Entry 0x8827 missing in IFD 0");
  				Assert.IsNotNull (entry as ShortIFDEntry, "Entry is not a short!");
  				Assert.AreEqual (200, (entry as ShortIFDEntry).Value);
  			}
  			// Photo.0x9003 (DateTimeOriginal/Ascii/20) "2010:01:02 13:45:49"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.DateTimeOriginal);
  				Assert.IsNotNull (entry, "Entry 0x9003 missing in IFD 0");
  				Assert.IsNotNull (entry as StringIFDEntry, "Entry is not a string!");
  				Assert.AreEqual ("2010:01:02 13:45:49", (entry as StringIFDEntry).Value);
  			}
  			// Photo.0x9004 (DateTimeDigitized/Ascii/20) "2010:01:02 13:45:49"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.DateTimeDigitized);
  				Assert.IsNotNull (entry, "Entry 0x9004 missing in IFD 0");
  				Assert.IsNotNull (entry as StringIFDEntry, "Entry is not a string!");
  				Assert.AreEqual ("2010:01:02 13:45:49", (entry as StringIFDEntry).Value);
  			}
  			// Photo.0x9201 (ShutterSpeedValue/Rational/1) "193557/32768"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.ShutterSpeedValue);
  				Assert.IsNotNull (entry, "Entry 0x9201 missing in IFD 0");
  				Assert.IsNotNull (entry as RationalIFDEntry, "Entry is not a rational!");
  				Assert.AreEqual (193557, (entry as RationalIFDEntry).Value.Numerator);
  				Assert.AreEqual (32768, (entry as RationalIFDEntry).Value.Denominator);
  			}
  			// Photo.0x9202 (ApertureValue/Rational/1) "1261433/262144"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.ApertureValue);
  				Assert.IsNotNull (entry, "Entry 0x9202 missing in IFD 0");
  				Assert.IsNotNull (entry as RationalIFDEntry, "Entry is not a rational!");
  				Assert.AreEqual (1261433, (entry as RationalIFDEntry).Value.Numerator);
  				Assert.AreEqual (262144, (entry as RationalIFDEntry).Value.Denominator);
  			}
  			// Photo.0x9204 (ExposureBiasValue/SRational/1) "0/6"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.ExposureBiasValue);
  				Assert.IsNotNull (entry, "Entry 0x9204 missing in IFD 0");
  				Assert.IsNotNull (entry as SRationalIFDEntry, "Entry is not a srational!");
  				Assert.AreEqual (0, (entry as SRationalIFDEntry).Value.Numerator);
  				Assert.AreEqual (6, (entry as SRationalIFDEntry).Value.Denominator);
  			}
  			// Photo.0x9205 (MaxApertureValue/Rational/1) "49/10"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.MaxApertureValue);
  				Assert.IsNotNull (entry, "Entry 0x9205 missing in IFD 0");
  				Assert.IsNotNull (entry as RationalIFDEntry, "Entry is not a rational!");
  				Assert.AreEqual (49, (entry as RationalIFDEntry).Value.Numerator);
  				Assert.AreEqual (10, (entry as RationalIFDEntry).Value.Denominator);
  			}
  			// Photo.0x9207 (MeteringMode/Short/1) "5"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.MeteringMode);
  				Assert.IsNotNull (entry, "Entry 0x9207 missing in IFD 0");
  				Assert.IsNotNull (entry as ShortIFDEntry, "Entry is not a short!");
  				Assert.AreEqual (5, (entry as ShortIFDEntry).Value);
  			}
  			// Photo.0x9208 (LightSource/Short/1) "0"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.LightSource);
  				Assert.IsNotNull (entry, "Entry 0x9208 missing in IFD 0");
  				Assert.IsNotNull (entry as ShortIFDEntry, "Entry is not a short!");
  				Assert.AreEqual (0, (entry as ShortIFDEntry).Value);
  			}
  			// Photo.0x9209 (Flash/Short/1) "0"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.Flash);
  				Assert.IsNotNull (entry, "Entry 0x9209 missing in IFD 0");
  				Assert.IsNotNull (entry as ShortIFDEntry, "Entry is not a short!");
  				Assert.AreEqual (0, (entry as ShortIFDEntry).Value);
  			}
  			// Photo.0x920A (FocalLength/Rational/1) "120/1"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.FocalLength);
  				Assert.IsNotNull (entry, "Entry 0x920A missing in IFD 0");
  				Assert.IsNotNull (entry as RationalIFDEntry, "Entry is not a rational!");
  				Assert.AreEqual (120, (entry as RationalIFDEntry).Value.Numerator);
  				Assert.AreEqual (1, (entry as RationalIFDEntry).Value.Denominator);
  			}
  			// Photo.0x9290 (SubSecTime/Ascii/4) "617"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.SubsecTime);
  				Assert.IsNotNull (entry, "Entry 0x9290 missing in IFD 0");
  				Assert.IsNotNull (entry as StringIFDEntry, "Entry is not a string!");
  				Assert.AreEqual ("617", (entry as StringIFDEntry).Value);
  			}
  			// Photo.0x9291 (SubSecTimeOriginal/Ascii/3) "00"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.SubsecTimeOriginal);
  				Assert.IsNotNull (entry, "Entry 0x9291 missing in IFD 0");
  				Assert.IsNotNull (entry as StringIFDEntry, "Entry is not a string!");
  				Assert.AreEqual ("00", (entry as StringIFDEntry).Value);
  			}
  			// Photo.0x9292 (SubSecTimeDigitized/Ascii/3) "00"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.SubsecTimeDigitized);
  				Assert.IsNotNull (entry, "Entry 0x9292 missing in IFD 0");
  				Assert.IsNotNull (entry as StringIFDEntry, "Entry is not a string!");
  				Assert.AreEqual ("00", (entry as StringIFDEntry).Value);
  			}
  			// Photo.0xA217 (SensingMethod/Byte/1) "2 "
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.SensingMethod);
  				Assert.IsNotNull (entry, "Entry 0xA217 missing in IFD 0");
  				Assert.IsNotNull (entry as ByteIFDEntry, "Entry is not a byte!");
  				Assert.AreEqual (2, (entry as ByteIFDEntry).Value);
  			}
  			// Photo.0xA301 (SceneType/Byte/1) "1 "
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.SceneType);
  				Assert.IsNotNull (entry, "Entry 0xA301 missing in IFD 0");
  				Assert.IsNotNull (entry as ByteIFDEntry, "Entry is not a byte!");
  				Assert.AreEqual (1, (entry as ByteIFDEntry).Value);
  			}
  			// Photo.0xA402 (ExposureMode/Short/1) "0"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.ExposureMode);
  				Assert.IsNotNull (entry, "Entry 0xA402 missing in IFD 0");
  				Assert.IsNotNull (entry as ShortIFDEntry, "Entry is not a short!");
  				Assert.AreEqual (0, (entry as ShortIFDEntry).Value);
  			}
  			// Photo.0xA403 (WhiteBalance/Short/1) "0"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.WhiteBalance);
  				Assert.IsNotNull (entry, "Entry 0xA403 missing in IFD 0");
  				Assert.IsNotNull (entry as ShortIFDEntry, "Entry is not a short!");
  				Assert.AreEqual (0, (entry as ShortIFDEntry).Value);
  			}
  			// Photo.0xA405 (FocalLengthIn35mmFilm/Short/1) "180"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.FocalLengthIn35mmFilm);
  				Assert.IsNotNull (entry, "Entry 0xA405 missing in IFD 0");
  				Assert.IsNotNull (entry as ShortIFDEntry, "Entry is not a short!");
  				Assert.AreEqual (180, (entry as ShortIFDEntry).Value);
  			}
  			// Photo.0xA406 (SceneCaptureType/Short/1) "0"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.SceneCaptureType);
  				Assert.IsNotNull (entry, "Entry 0xA406 missing in IFD 0");
  				Assert.IsNotNull (entry as ShortIFDEntry, "Entry is not a short!");
  				Assert.AreEqual (0, (entry as ShortIFDEntry).Value);
  			}
  			// Photo.0xA408 (Contrast/Short/1) "0"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.Contrast);
  				Assert.IsNotNull (entry, "Entry 0xA408 missing in IFD 0");
  				Assert.IsNotNull (entry as ShortIFDEntry, "Entry is not a short!");
  				Assert.AreEqual (0, (entry as ShortIFDEntry).Value);
  			}
  			// Photo.0xA409 (Saturation/Short/1) "0"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.Saturation);
  				Assert.IsNotNull (entry, "Entry 0xA409 missing in IFD 0");
  				Assert.IsNotNull (entry as ShortIFDEntry, "Entry is not a short!");
  				Assert.AreEqual (0, (entry as ShortIFDEntry).Value);
  			}
  			// Photo.0xA40A (Sharpness/Short/1) "0"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.Sharpness);
  				Assert.IsNotNull (entry, "Entry 0xA40A missing in IFD 0");
  				Assert.IsNotNull (entry as ShortIFDEntry, "Entry is not a short!");
  				Assert.AreEqual (0, (entry as ShortIFDEntry).Value);
  			}
  			// Photo.0xA40C (SubjectDistanceRange/Short/1) "0"
  			{
  				var entry = exif_structure.GetEntry (0, (ushort)ExifEntryTag.SubjectDistanceRange);
  				Assert.IsNotNull (entry, "Entry 0xA40C missing in IFD 0");
  				Assert.IsNotNull (entry as ShortIFDEntry, "Entry is not a short!");
  				Assert.AreEqual (0, (entry as ShortIFDEntry).Value);
  			}
  
  			//  ---------- End of IFD tests ----------
  
  
  			//  ---------- Start of XMP tests ----------
  
  			var xmp = file.GetTag (TagTypes.XMP) as XmpTag;
  			// Xmp.tiff.Model (XmpText/9) "NIKON D90"
  			{
  				var node = xmp.NodeTree;
  				node = node.GetChild (XmpTag.TIFF_NS, "Model");
  				Assert.IsNotNull (node);
  				Assert.AreEqual ("NIKON D90", node.Value);
  				Assert.AreEqual (XmpNodeType.Simple, node.Type);
  				Assert.AreEqual (0, node.Children.Count);
  			}
  			// Xmp.tiff.Make (XmpText/17) "NIKON CORPORATION"
  			{
  				var node = xmp.NodeTree;
  				node = node.GetChild (XmpTag.TIFF_NS, "Make");
  				Assert.IsNotNull (node);
  				Assert.AreEqual ("NIKON CORPORATION", node.Value);
  
gt: 				Assert.AreEqual (XmpNodeType.Simple, node.Type);