public FileExpectations(FileExpectations other)
            : this(other.timeZoneForDateTime)
        {
            this.DateTime = other.DateTime;
            this.DarkPixelFraction = other.DarkPixelFraction;
            this.DeleteFlag = other.DeleteFlag;
            this.FileName = other.FileName;
            this.ID = other.ID;
            this.IsColor = other.IsColor;
            this.Quality = other.Quality;
            this.RelativePath = other.RelativePath;
            this.SkipDateTimeVerification = other.SkipDateTimeVerification;

            foreach (KeyValuePair<string, string> columnExpectation in other.UserDefinedColumnsByDataLabel)
            {
                this.UserDefinedColumnsByDataLabel.Add(columnExpectation.Key, columnExpectation.Value);
            }
        }
        public void MoveFile()
        {
            // remove any existing files from previous test executions
            string sourceFilePath = Path.Combine(Environment.CurrentDirectory, "DatabaseTests.MoveFile.jpg");
            if (File.Exists(sourceFilePath))
            {
                File.Delete(sourceFilePath);
            }
            string subfolderPath = Path.Combine(Environment.CurrentDirectory, "DatabaseTests.MoveFileFolder");
            if (Directory.Exists(subfolderPath) == false)
            {
                Directory.CreateDirectory(subfolderPath);
            }
            string destinationFilePath = Path.Combine(subfolderPath, Path.GetFileName(sourceFilePath));
            if (File.Exists(destinationFilePath))
            {
                File.Delete(destinationFilePath);
            }

            FileExpectations fileExpectation = new FileExpectations(TestConstant.FileExpectation.DaylightBobcat);
            fileExpectation.ID = Constant.Database.InvalidID;

            // create ImageRow object for file
            File.Copy(fileExpectation.FileName, sourceFilePath);
            FileInfo fileInfo = new FileInfo(sourceFilePath);

            FileDatabase fileDatabase = this.CreateFileDatabase(TestConstant.File.DefaultTemplateDatabaseFileName, TestConstant.File.DefaultNewFileDatabaseFileName);
            ImageRow file;
            fileDatabase.GetOrCreateFile(fileInfo, fileDatabase.ImageSet.GetTimeZone(), out file);
            TimeZoneInfo imageSetTimeZone = fileDatabase.ImageSet.GetTimeZone();
            file.TryReadDateTimeOriginalFromMetadata(fileDatabase.FolderPath, imageSetTimeZone);

            fileExpectation.FileName = Path.GetFileName(sourceFilePath);
            fileExpectation.Verify(file, imageSetTimeZone);

            // move file
            Assert.IsTrue(file.TryMoveToFolder(fileDatabase.FolderPath, subfolderPath, false));
            fileExpectation.RelativePath = Path.GetFileName(subfolderPath);
            fileExpectation.Verify(file, imageSetTimeZone);

            // move file back
            Assert.IsTrue(file.TryMoveToFolder(fileDatabase.FolderPath, fileDatabase.FolderPath, false));
            fileExpectation.RelativePath = null;
            fileExpectation.Verify(file, imageSetTimeZone);
        }
        public void FileDatabaseVerfication()
        {
            // load database
            string fileDatabaseBaseFileName = TestConstant.File.DefaultFileDatabaseFileName;
            FileDatabase fileDatabase = this.CloneFileDatabase(TestConstant.File.DefaultTemplateDatabaseFileName, fileDatabaseBaseFileName);
            Assert.IsTrue(fileDatabase.ControlSynchronizationIssues.Count == 0);

            fileDatabase.SelectFiles(FileSelection.All);
            Assert.IsTrue(fileDatabase.Files.RowCount > 0);

            // verify template portion
            this.VerifyTemplateDatabase(fileDatabase, fileDatabaseBaseFileName);
            DefaultTemplateTableExpectation templateTableExpectation = new DefaultTemplateTableExpectation(new Version(2, 2, 0, 0));
            templateTableExpectation.Verify(fileDatabase);

            // verify image set table
            this.VerifyDefaultImageSet(fileDatabase);

            // verify markers table
            int filesExpected = 2;
            this.VerifyDefaultMarkerTableContent(fileDatabase, filesExpected);

            MarkerExpectation martenMarkerExpectation = new MarkerExpectation();
            martenMarkerExpectation.ID = 1;
            martenMarkerExpectation.UserDefinedCountersByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Counter0, "0.498,0.575|0.550,0.566|0.584,0.555");
            martenMarkerExpectation.UserDefinedCountersByDataLabel.Add(TestConstant.DefaultDatabaseColumn.CounterWithCustomDataLabel, String.Empty);
            martenMarkerExpectation.UserDefinedCountersByDataLabel.Add(TestConstant.DefaultDatabaseColumn.CounterNotVisible, String.Empty);
            martenMarkerExpectation.UserDefinedCountersByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Counter3, String.Empty);
            martenMarkerExpectation.Verify(fileDatabase.Markers[0]);

            MarkerExpectation bobcatMarkerExpectation = new MarkerExpectation();
            bobcatMarkerExpectation.ID = 2;
            bobcatMarkerExpectation.UserDefinedCountersByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Counter0, String.Empty);
            bobcatMarkerExpectation.UserDefinedCountersByDataLabel.Add(TestConstant.DefaultDatabaseColumn.CounterWithCustomDataLabel, String.Empty);
            bobcatMarkerExpectation.UserDefinedCountersByDataLabel.Add(TestConstant.DefaultDatabaseColumn.CounterNotVisible, String.Empty);
            bobcatMarkerExpectation.UserDefinedCountersByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Counter3, String.Empty);
            bobcatMarkerExpectation.Verify(fileDatabase.Markers[1]);

            // verify Files
            Assert.IsTrue(fileDatabase.Files.ColumnNames.Count() == TestConstant.DefaultFileDataColumns.Count);
            Assert.IsTrue(fileDatabase.Files.RowCount == filesExpected);

            TimeZoneInfo imageSetTimeZone = fileDatabase.ImageSet.GetTimeZone();
            FileExpectations martenExpectation = new FileExpectations(TestConstant.FileExpectation.InfraredMarten);
            martenExpectation.ID = 1;
            martenExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Counter0, "3");
            martenExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Choice0, "choice c");
            martenExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Note0, "0");
            martenExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Flag0, Boolean.TrueString);
            martenExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.CounterWithCustomDataLabel, "100");
            martenExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.ChoiceWithCustomDataLabel, "Genus species");
            martenExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.NoteWithCustomDataLabel, "custom label");
            martenExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.FlagWithCustomDataLabel, Boolean.FalseString);
            martenExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.CounterNotVisible, templateTableExpectation.CounterNotVisible.DefaultValue);
            martenExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.ChoiceNotVisible, Constant.ControlDefault.Value);
            martenExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.NoteNotVisible, Constant.ControlDefault.Value);
            martenExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.FlagNotVisible, Constant.ControlDefault.FlagValue);
            martenExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Counter3, "1");
            martenExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Choice3, Constant.ControlDefault.Value);
            martenExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Note3, "note");
            martenExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Flag3, Boolean.TrueString);
            martenExpectation.Verify(fileDatabase.Files[0], imageSetTimeZone);

            FileExpectations bobcatExpectation = new FileExpectations(TestConstant.FileExpectation.DaylightBobcat);
            bobcatExpectation.ID = 2;
            bobcatExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Counter0, templateTableExpectation.Counter0.DefaultValue);
            bobcatExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Choice0, "choice a");
            bobcatExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Note0, "1");
            bobcatExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Flag0, Boolean.TrueString);
            bobcatExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.CounterWithCustomDataLabel, "3");
            bobcatExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.ChoiceWithCustomDataLabel, "with , comma");
            bobcatExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.NoteWithCustomDataLabel, Constant.ControlDefault.Value);
            bobcatExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.FlagWithCustomDataLabel, Boolean.TrueString);
            bobcatExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.CounterNotVisible, templateTableExpectation.CounterNotVisible.DefaultValue);
            bobcatExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.ChoiceNotVisible, Constant.ControlDefault.Value);
            bobcatExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.NoteNotVisible, Constant.ControlDefault.Value);
            bobcatExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.FlagNotVisible, Constant.ControlDefault.FlagValue);
            bobcatExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Counter3, templateTableExpectation.Counter3.DefaultValue);
            bobcatExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Choice3, Constant.ControlDefault.Value);
            bobcatExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Note3, Constant.ControlDefault.Value);
            bobcatExpectation.UserDefinedColumnsByDataLabel.Add(TestConstant.DefaultDatabaseColumn.Flag3, Boolean.TrueString);
            bobcatExpectation.Verify(fileDatabase.Files[1], imageSetTimeZone);
        }
        private void TimeZones(string initialTimeZoneID, string secondTimeZoneID)
        {
            // create file database and populate images in initial time zone
            // TimeZoneInfo doesn't implement operator == so Equals() must be called
            FileDatabase fileDatabase = this.CreateFileDatabase(TestConstant.File.DefaultTemplateDatabaseFileName, Constant.File.DefaultFileDatabaseFileName);
            Assert.IsTrue(fileDatabase.ImageSet.TimeZone == TimeZoneInfo.Local.Id);
            Assert.IsTrue(TimeZoneInfo.Local.Equals(fileDatabase.ImageSet.GetTimeZone()));

            fileDatabase.ImageSet.TimeZone = initialTimeZoneID;
            fileDatabase.SyncImageSetToDatabase();

            TimeZoneInfo initialImageSetTimeZone = TimeZoneInfo.FindSystemTimeZoneById(initialTimeZoneID);
            Assert.IsTrue(fileDatabase.ImageSet.TimeZone == initialTimeZoneID);
            Assert.IsTrue(initialImageSetTimeZone.Equals(fileDatabase.ImageSet.GetTimeZone()));

            List<FileExpectations> fileExpectations = this.PopulateDefaultDatabase(fileDatabase, true);

            // change to second time zone
            fileDatabase.ImageSet.TimeZone = secondTimeZoneID;
            fileDatabase.SyncImageSetToDatabase();

            TimeZoneInfo secondImageSetTimeZone = TimeZoneInfo.FindSystemTimeZoneById(secondTimeZoneID);
            Assert.IsTrue(fileDatabase.ImageSet.TimeZone == secondTimeZoneID);
            Assert.IsTrue(secondImageSetTimeZone.Equals(fileDatabase.ImageSet.GetTimeZone()));

            // verify date times of existing images haven't changed
            int initialFileCount = fileDatabase.Files.RowCount;
            this.VerifyFiles(fileDatabase, fileExpectations, initialImageSetTimeZone, initialFileCount, secondImageSetTimeZone);

            // add more images
            DateTimeAdjustment timeAdjustment;
            ImageRow martenPairImage = this.CreateFile(fileDatabase, secondImageSetTimeZone, TestConstant.FileExpectation.DaylightMartenPair, out timeAdjustment);
            ImageRow coyoteImage = this.CreateFile(fileDatabase, secondImageSetTimeZone, TestConstant.FileExpectation.DaylightCoyote, out timeAdjustment);

            fileDatabase.AddFiles(new List<ImageRow>() { martenPairImage, coyoteImage }, null);
            fileDatabase.SelectFiles(FileSelection.All);

            // generate expectations for new images
            FileExpectations martenPairExpectation = new FileExpectations(TestConstant.FileExpectation.DaylightMartenPair);
            martenPairExpectation.ID = fileExpectations.Count + 1;
            fileExpectations.Add(martenPairExpectation);

            FileExpectations daylightCoyoteExpectation = new FileExpectations(TestConstant.FileExpectation.DaylightCoyote);
            daylightCoyoteExpectation.ID = fileExpectations.Count + 1;
            fileExpectations.Add(daylightCoyoteExpectation);

            // verify new images pick up the current timezone
            this.VerifyFiles(fileDatabase, fileExpectations, initialImageSetTimeZone, initialFileCount, secondImageSetTimeZone);
        }
 /// <summary>
 /// Creates a data row from the specified FileExpectation.  Verifies the file isn't already in the database and does not add it to the database.
 /// </summary>
 protected ImageRow CreateFile(FileDatabase fileDatabase, TimeZoneInfo imageSetTimeZone, FileExpectations fileExpectation, out DateTimeAdjustment dateTimeAdjustment)
 {
     FileInfo fileInfo = new FileInfo(Path.Combine(this.WorkingDirectory, fileExpectation.RelativePath, fileExpectation.FileName));
     ImageRow file;
     Assert.IsFalse(fileDatabase.GetOrCreateFile(fileInfo, imageSetTimeZone, out file));
     dateTimeAdjustment = file.TryReadDateTimeOriginalFromMetadata(fileDatabase.FolderPath, imageSetTimeZone);
     return file;
 }
 protected Dictionary<string, string> LoadMetadata(FileDatabase fileDatabase, FileExpectations fileExpectation)
 {
     string filePath = Path.Combine(this.WorkingDirectory, fileExpectation.RelativePath, fileExpectation.FileName);
     Dictionary<string, string> metadata = Utilities.LoadMetadata(filePath);
     Assert.IsTrue(metadata.Count > 40, "Expected at least 40 metadata fields to be retrieved from {0}", filePath);
     // example information returned from ExifTool
     // field name                   Bushnell                                    Reconyx
     // --- fields of likely interest for image analysis ---
     // Create Date                  2016.02.24 04:59:46                         [Bushnell only]
     // Date/Time Original           2016.02.24 04:59:46                         2015.01.28 11:17:34 [but located in Makernote rather than the standard EXIF field!]
     // Modify Date                  2016.02.24 04:59:46                         [Bushnell only]
     // --- fields possibly of interest interest for image analysis ---
     // Exposure Time                0                                           1/84
     // Shutter Speed                0                                           1/84
     // Software                     BS683BWYx05209                              [Bushnell only]
     // Firmware Version             [Reconyx only]                              3.3.0
     // Trigger Mode                 [Reconyx only]                              Motion Detection
     // Sequence                     [Reconyx only]                              1 of 5
     // Ambient Temperature          [Reconyx only]                              0 C
     // Serial Number                [Reconyx only]                              H500DE01120343
     // Infrared Illuminator         [Reconyx only]                              Off
     // User Label                   [Reconyx only]                              CCPF DS02
     // --- fields of little interest (Bushnell often uses placeholder values which don't change) ---
     // ExifTool Version Number      10.14                                       10.14
     // File Name                    BushnellTrophyHD-119677C-20160224-056.JPG   Reconyx-HC500-20150128-201.JPG
     // Directory                    Carnassial/UnitTests/bin/Debug               Carnassial/UnitTests/bin/Debug/CarnivoreTestImages
     // File Size                    731 kB                                      336 kB
     // File Modification Date/Time  <file time from last build>                 <file time from last build>
     // File Access Date/Time        <file time from last build>                 <file time from last build>
     // File Creation Date/Time      <file time from last build>                 <file time from last build>
     // File Permissions             rw-rw-rw-                                   rw-rw-rw-
     // File Type                    JPEG                                        JPEG
     // File Type Extension          jpg                                         jpg
     // MIME Type                    image/jpeg                                  image/jpeg
     // Exif Byte Order              Little-endian(Intel, II)                    Little-endian(Intel, II)
     // Image Description            M2E6L0-0R350B362                            [Bushnell only]
     // Make                         [blank]                                     [Bushnell only]
     // Camera Model Name            [blank]                                     [Bushnell only]
     // Orientation                  Horizontal(normal)                          [Bushnell only]
     // X Resolution                 96                                          72
     // Y Resolution                 96                                          72
     // Resolution Unit              inches                                      inches
     // Y Cb Cr Positioning          Co-sited                                    Co-sited
     // Copyright                    Copyright 2002                              [Bushnell only]
     // F Number                     2.8                                         [Bushnell only]
     // Exposure Program             Aperture-priority AE                        [Bushnell only]
     // ISO                          100                                         50
     // Exif Version                 0210                                        0220
     // Components Configuration     Y, Cb, Cr, -                                Y, Cb, Cr, -
     // Compressed Bits Per Pixel    0.7419992711                                [Bushnell only]
     // Shutter Speed Value          1                                           [Bushnell only]
     // Aperture Value               2.6                                         [Bushnell only]
     // Exposure Compensation        +2                                          [Bushnell only]
     // Max Aperture Value           2.6                                         [Bushnell only]
     // Metering Mode                Average                                     [Bushnell only]
     // Light Source                 Daylight                                    [Bushnell only]
     // Flash                        No Flash                                    [Bushnell only]
     // Warning                      [minor]Unrecognized MakerNotes              [Bushnell only]
     // Flashpix Version             0100                                        0100
     // Color Space                  sRGB                                        sRGB
     // Exif Image Width             3264                                        2048
     // Exif Image Height            2448                                        1536
     // Related Sound File           RelatedSound                                [Bushnell only]
     // Interoperability Index       R98 - DCF basic file(sRGB)                  [Bushnell only]
     // Interoperability Version     0100                                        [Bushnell only]
     // Exposure Index               1                                           [Bushnell only]
     // Sensing Method               One-chip color area                         [Bushnell only]
     // File Source                  Digital Camera                              [Bushnell only]
     // Scene Type                   Directly photographed                       [Bushnell only]
     // Compression                  JPEG(old - style)                           [Bushnell only]
     // Thumbnail Offset             1312                                        [Bushnell only]
     // Thumbnail Length             5768                                        [Bushnell only]
     // Image Width                  3264                                        2048
     // Image Height                 2448                                        1536
     // Encoding Process             Baseline DCT, Huffman coding                Baseline DCT, Huffman coding
     // Bits Per Sample              8                                           8
     // Color Components             3                                           3
     // Y Cb Cr Sub Sampling         YCbCr4:2:2 (2 1)                            YCbCr4:2:2 (2 1)
     // Aperture                     2.8                                         [Bushnell only]
     // Image Size                   3264x2448                                   2048x1536
     // Megapixels                   8.0                                         3.1
     // Thumbnail Image              <binary data>                               [Bushnell only]
     // Ambient Temperature Fahrenheit [Reconyx only]                            31 F
     // Battery Voltage              [Reconyx only]                              8.65 V
     // Contrast                     [Reconyx only]                              142
     // Brightness                   [Reconyx only]                              238
     // Event Number                 [Reconyx only]                              39
     // Firmware Date                [Reconyx only]                              2011:01:10
     // Maker Note Version           [Reconyx only]                              0xf101
     // Moon Phase                   [Reconyx only]                              First Quarter
     // Motion Sensitivity           [Reconyx only]                              100
     // Sharpness                    [Reconyx only]                              64
     // Saturation                   [Reconyx only]                              144
     return metadata;
 }