public void TestCorruptDataHandling(
            string rawFileName,
            int scanStart,
            int scanEnd,
            int expectedMS1,
            int expectedMS2,
            int corruptScanStart,
            int corruptScanEnd)
        {
            var dataFile = GetRawDataFile(rawFileName);

            try
            {

                using (var reader = new XRawFileIO(dataFile.FullName))
                {
                    var scanCount = reader.GetNumScans();
                    Console.WriteLine("Scan count for {0}: {1}", dataFile.Name, scanCount);

                    if (expectedMS1 + expectedMS2 == 0)
                    {
                        Assert.IsTrue(reader.FileInfo.CorruptFile, "CorruptFile is false while we expected it to be true");
                        Assert.IsTrue(scanCount == 0, "ScanCount is non-zero, while we expected it to be 0");
                    }
                    else
                    {
                        Assert.IsFalse(reader.FileInfo.CorruptFile, "CorruptFile is true while we expected it to be false");
                        Assert.IsTrue(scanCount > 0, "ScanCount is zero, while we expected it to be > 0");
                    }

                    var scanCountMS1 = 0;
                    var scanCountMS2 = 0;

                    for (var scanNumber = scanStart; scanNumber <= scanEnd; scanNumber++)
                    {
                        try
                        {
                            clsScanInfo scanInfo;
                            reader.GetScanInfo(scanNumber, out scanInfo);

                            if (reader.FileInfo.CorruptFile)
                            {
                                Assert.IsTrue(string.IsNullOrEmpty(scanInfo.FilterText), "FilterText is not empty but should be since corrupt file");
                            }
                            else
                            {
                                Assert.IsFalse(string.IsNullOrEmpty(scanInfo.FilterText), "FilterText is empty but should not be");

                                if (scanInfo.MSLevel > 1)
                                    scanCountMS2++;
                                else
                                    scanCountMS1++;
                            }

                            double[] mzList;
                            double[] intensityList;

                            // Note: this function call will fail randomly with file Corrupt_Scans6920-7021_AID_STM_013_101104_06_LTQ_16Nov04_Earth_0904-8.raw
                            // Furthermore, we are unable to catch the exception that occurs (or no exception is thrown) and adding
                            // [System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions] to the function does not help
                            var dataPointCount = reader.GetScanData(scanNumber, out mzList, out intensityList);

                            if (reader.FileInfo.CorruptFile)
                            {
                                Assert.IsTrue(dataPointCount == 0, "GetScanData unexpectedly reported a non-zero data count for scan {0}", scanNumber);
                                Assert.IsTrue(mzList.Length == 0, "GetScanData unexpectedly returned m/z data for scan {0}", scanNumber);
                                Assert.IsTrue(intensityList.Length == 0, "GetScanData unexpectedly returned intensity data for scan {0}", scanNumber);
                            }
                            else
                            {
                                if (dataPointCount == 0)
                                {
                                    Console.WriteLine("Corrupt scan encountered: {0}", scanNumber);

                                    Assert.IsTrue(scanNumber >= corruptScanStart && scanNumber <= corruptScanEnd, "Unexpected corrupt scan found, scan {0}", scanNumber);
                                    Assert.IsTrue(mzList.Length == 0, "GetScanData unexpectedly returned m/z data for scan {0}", scanNumber);
                                    Assert.IsTrue(intensityList.Length == 0, "GetScanData unexpectedly returned intensity data for scan {0}", scanNumber);
                                }
                                else
                                {
                                    Assert.IsTrue(dataPointCount > 0, "GetScanData reported a data point count of 0 for scan {0}", scanNumber);
                                    Assert.IsTrue(mzList.Length > 0, "GetScanData unexpectedly returned no m/z data for scan {0}", scanNumber);
                                    Assert.IsTrue(intensityList.Length > 0, "GetScanData unexpectedly returned no intensity data for scan {0}", scanNumber);
                                    Assert.IsTrue(mzList.Length == intensityList.Length, "Array length mismatch for m/z and intensity data for scan {0}", scanNumber);
                                    Assert.IsTrue(dataPointCount == mzList.Length, "Array length does not agree with dataPointCount for scan {0}", scanNumber);
                                }
                            }

                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("Exception reading scan {0}: {1}", scanNumber, ex.Message);
                            Assert.Fail("Exception reading scan {0}", scanNumber);
                        }
                    }

                    Console.WriteLine("scanCountMS1={0}", scanCountMS1);
                    Console.WriteLine("scanCountMS2={0}", scanCountMS2);

                    Assert.AreEqual(expectedMS1, scanCountMS1, "MS1 scan count mismatch");
                    Assert.AreEqual(expectedMS2, scanCountMS2, "MS2 scan count mismatch");

                }
            }
            catch (Exception ex)
            {
                var msg = string.Format("Exception opening .raw file {0}:\n{1}", rawFileName, ex.Message);
                Console.WriteLine(msg);
                Assert.Fail(msg);
            }
        }
        public void TestGetScanData(string rawFileName, int scanStart, int scanEnd)
        {
            var expectedData = new Dictionary<string, Dictionary<int, Dictionary<string, string>>>();

            // Keys in this dictionary are the scan number of data being retrieved
            var file1Data = new Dictionary<int, Dictionary<string, string>>
            {
                {1513, new Dictionary<string, string>()},
                {1514, new Dictionary<string, string>()},
                {1515, new Dictionary<string, string>()},
                {1516, new Dictionary<string, string>()},
                {1517, new Dictionary<string, string>()}
            };

            // The KeySpec for each dictionary entry is MaxDataCount_Centroid
            file1Data[1513].Add("0_False",  " 851      851  409.615   4.8E+5 1227.956   1.6E+6  + c ESI Full ms [400.00-2000.00]");
            file1Data[1514].Add("0_False",  " 109      109  281.601   2.4E+4  633.151   4.4E+4  + c d Full ms2 [email protected] [230.00-1780.00]");
            file1Data[1515].Add("0_False",  " 290      290  335.798   3.8E+4 1034.194   1.6E+4  + c d Full ms2 [email protected] [305.00-2000.00]");
            file1Data[1516].Add("0_False",  " 154      154  461.889   7.3E+3 1203.274   2.6E+3  + c d Full ms2 [email protected] [400.00-2000.00]");
            file1Data[1517].Add("0_False",  " 887      887  420.016   9.7E+5 1232.206   8.0E+5  + c ESI Full ms [400.00-2000.00]");

            file1Data[1513].Add("0_True",   " 851      851  409.615   4.8E+5 1227.956   1.6E+6  + c ESI Full ms [400.00-2000.00]");
            file1Data[1514].Add("0_True",   " 109      109  281.601   2.4E+4  633.151   4.4E+4  + c d Full ms2 [email protected] [230.00-1780.00]");
            file1Data[1515].Add("0_True",   " 290      290  335.798   3.8E+4 1034.194   1.6E+4  + c d Full ms2 [email protected] [305.00-2000.00]");
            file1Data[1516].Add("0_True",   " 154      154  461.889   7.3E+3 1203.274   2.6E+3  + c d Full ms2 [email protected] [400.00-2000.00]");
            file1Data[1517].Add("0_True",   " 887      887  420.016   9.7E+5 1232.206   8.0E+5  + c ESI Full ms [400.00-2000.00]");

            file1Data[1513].Add("50_False", "  50       50  747.055   2.5E+6 1148.485   3.4E+6  + c ESI Full ms [400.00-2000.00]");
            file1Data[1514].Add("50_False", "  50       50  281.601   2.4E+4  632.089   2.6E+4  + c d Full ms2 [email protected] [230.00-1780.00]");
            file1Data[1515].Add("50_False", "  50       50  353.590   9.7E+4 1157.949   3.6E+5  + c d Full ms2 [email protected] [305.00-2000.00]");
            file1Data[1516].Add("50_False", "  50       50  461.889   7.3E+3 1146.341   1.4E+4  + c d Full ms2 [email protected] [400.00-2000.00]");
            file1Data[1517].Add("50_False", "  50       50  883.347   8.9E+6 1206.792   5.5E+6  + c ESI Full ms [400.00-2000.00]");

            file1Data[1513].Add("50_True",  "  50       50  747.055   2.5E+6 1148.485   3.4E+6  + c ESI Full ms [400.00-2000.00]");
            file1Data[1514].Add("50_True",  "  50       50  281.601   2.4E+4  632.089   2.6E+4  + c d Full ms2 [email protected] [230.00-1780.00]");
            file1Data[1515].Add("50_True",  "  50       50  353.590   9.7E+4 1157.949   3.6E+5  + c d Full ms2 [email protected] [305.00-2000.00]");
            file1Data[1516].Add("50_True",  "  50       50  461.889   7.3E+3 1146.341   1.4E+4  + c d Full ms2 [email protected] [400.00-2000.00]");
            file1Data[1517].Add("50_True",  "  50       50  883.347   8.9E+6 1206.792   5.5E+6  + c ESI Full ms [400.00-2000.00]");

            expectedData.Add("Shew_246a_LCQa_15Oct04_Andro_0904-2_4-20", file1Data);

            var file2Data = new Dictionary<int, Dictionary<string, string>>
            {
                {16121, new Dictionary<string, string>()},
                {16122, new Dictionary<string, string>()},
                {16126, new Dictionary<string, string>()},
                {16131, new Dictionary<string, string>()},
                {16133, new Dictionary<string, string>()},
                {16141, new Dictionary<string, string>()}
            };

            // The KeySpec for each dictionary entry is MaxDataCount_Centroid
            file2Data[16121].Add("0_False", "11888    11888  346.518   0.0E+0  706.844   9.8E+4  FTMS + p NSI Full ms [350.0000-1550.0000]");
            file2Data[16122].Add("0_False", "  490      490  116.232   7.0E+1  403.932   1.1E+3  ITMS + c NSI r d Full ms2 [email protected] [106.0000-817.0000]");
            file2Data[16126].Add("0_False", "  753      753  231.045   1.1E+1 1004.586   2.0E+1  ITMS + c NSI r d sa Full ms2 [email protected]@cid20.00 [120.0000-1627.0000]");
            file2Data[16131].Add("0_False", "   29       29  984.504   9.5E+3 1931.917   2.4E+1  ITMS + c NSI r d Full ms2 [email protected] [120.0000-1986.0000]");
            file2Data[16133].Add("0_False", "  280      280  260.118   2.3E+1  663.160   7.7E+0  ITMS + c NSI r d sa Full ms2 [email protected]@cid20.00 [120.0000-853.0000]");
            file2Data[16141].Add("0_False", "  240      240  304.425   1.3E+1 1447.649   3.0E+1  ITMS + c NSI r d sa Full ms2 [email protected]@hcd20.00 [120.0000-1760.0000]");

            file2Data[16121].Add("0_True", "  833      833  351.231   2.9E+5  712.813   2.9E+5  FTMS + p NSI Full ms [350.0000-1550.0000]");
            file2Data[16122].Add("0_True", "  490      490  116.232   7.0E+1  403.932   1.1E+3  ITMS + c NSI r d Full ms2 [email protected] [106.0000-817.0000]");
            file2Data[16126].Add("0_True", "  753      753  231.045   1.1E+1 1004.586   2.0E+1  ITMS + c NSI r d sa Full ms2 [email protected]@cid20.00 [120.0000-1627.0000]");
            file2Data[16131].Add("0_True", "   29       29  984.504   9.5E+3 1931.917   2.4E+1  ITMS + c NSI r d Full ms2 [email protected] [120.0000-1986.0000]");
            file2Data[16133].Add("0_True", "  280      280  260.118   2.3E+1  663.160   7.7E+0  ITMS + c NSI r d sa Full ms2 [email protected]@cid20.00 [120.0000-853.0000]");
            file2Data[16141].Add("0_True", "  240      240  304.425   1.3E+1 1447.649   3.0E+1  ITMS + c NSI r d sa Full ms2 [email protected]@hcd20.00 [120.0000-1760.0000]");

            file2Data[16121].Add("50_False", "   50       50  503.553   2.0E+7  504.571   2.1E+7  FTMS + p NSI Full ms [350.0000-1550.0000]");
            file2Data[16122].Add("50_False", "   50       50  157.049   2.0E+4  385.181   6.0E+3  ITMS + c NSI r d Full ms2 [email protected] [106.0000-817.0000]");
            file2Data[16126].Add("50_False", "   50       50  535.311   2.5E+3  798.982   1.3E+3  ITMS + c NSI r d sa Full ms2 [email protected]@cid20.00 [120.0000-1627.0000]");
            file2Data[16131].Add("50_False", "   29       29  984.504   9.5E+3 1931.917   2.4E+1  ITMS + c NSI r d Full ms2 [email protected] [120.0000-1986.0000]");
            file2Data[16133].Add("50_False", "   50       50  356.206   7.5E+1  795.543   1.3E+2  ITMS + c NSI r d sa Full ms2 [email protected]@cid20.00 [120.0000-853.0000]");
            file2Data[16141].Add("50_False", "   50       50  853.937   5.6E+1 1705.974   9.8E+1  ITMS + c NSI r d sa Full ms2 [email protected]@hcd20.00 [120.0000-1760.0000]");

            file2Data[16121].Add("50_True", "  833      833  351.231   2.9E+5  712.813   2.9E+5  FTMS + p NSI Full ms [350.0000-1550.0000]");
            file2Data[16122].Add("50_True", "   50       50  157.049   2.0E+4  385.181   6.0E+3  ITMS + c NSI r d Full ms2 [email protected] [106.0000-817.0000]");
            file2Data[16126].Add("50_True", "   50       50  535.311   2.5E+3  798.982   1.3E+3  ITMS + c NSI r d sa Full ms2 [email protected]@cid20.00 [120.0000-1627.0000]");
            file2Data[16131].Add("50_True", "   29       29  984.504   9.5E+3 1931.917   2.4E+1  ITMS + c NSI r d Full ms2 [email protected] [120.0000-1986.0000]");
            file2Data[16133].Add("50_True", "   50       50  356.206   7.5E+1  795.543   1.3E+2  ITMS + c NSI r d sa Full ms2 [email protected]@cid20.00 [120.0000-853.0000]");
            file2Data[16141].Add("50_True", "   50       50  853.937   5.6E+1 1705.974   9.8E+1  ITMS + c NSI r d sa Full ms2 [email protected]@hcd20.00 [120.0000-1760.0000]");

            expectedData.Add("HCC-38_ETciD_EThcD_4xdil_20uL_3hr_3_08Jan16_Pippin_15-08-53", file2Data);

            var dataFile = GetRawDataFile(rawFileName);

            using (var reader = new XRawFileIO(dataFile.FullName))
            {

                for (var iteration = 1; iteration <= 4; iteration++)
                {
                    int maxNumberOfPeaks;
                    bool centroidData;

                    switch (iteration)
                    {
                        case 1:
                            maxNumberOfPeaks = 0;
                            centroidData = false;
                            break;
                        case 2:
                            maxNumberOfPeaks = 0;
                            centroidData = true;
                            break;
                        case 3:
                            maxNumberOfPeaks = 50;
                            centroidData = false;
                            break;
                        default:
                            maxNumberOfPeaks = 50;
                            centroidData = true;
                            break;
                    }

                    if (iteration == 1)
                    {
                        Console.WriteLine("Scan data for {0}", dataFile.Name);
                        Console.WriteLine("{0} {1,3} {2,8} {3,-8} {4,-8} {5,-8} {6,-8} {7,-8} {8,-8}  {9}",
                                          "Scan", "Max#", "Centroid", "MzCount", "IntCount",
                                          "FirstMz", "FirstInt", "MidMz", "MidInt", "ScanFilter");
                    }

                    for (var scanNumber = scanStart; scanNumber <= scanEnd; scanNumber++)
                    {

                        double[] mzList;
                        double[] intensityList;

                        var dataPointsRead = reader.GetScanData(scanNumber, out mzList, out intensityList, maxNumberOfPeaks, centroidData);

                        Assert.IsTrue(dataPointsRead > 0, "GetScanData returned 0 for scan {0}", scanNumber);

                        Assert.AreEqual(dataPointsRead, mzList.Length, "Data count mismatch vs. function return value");

                        var midPoint = (int)(intensityList.Length / 2f);

                        clsScanInfo scanInfo;
                        var success = reader.GetScanInfo(scanNumber, out scanInfo);

                        Assert.IsTrue(success, "GetScanInfo returned false for scan {0}", scanNumber);

                        var scanSummary =
                            string.Format(
                                "{0} {1,3} {2,8} {3,8} {4,8} {5,8} {6,8} {7,8} {8,8}  {9}",
                                scanNumber, maxNumberOfPeaks, centroidData,
                                mzList.Length, intensityList.Length,
                                mzList[0].ToString("0.000"), intensityList[0].ToString("0.0E+0"),
                                mzList[midPoint].ToString("0.000"), intensityList[midPoint].ToString("0.0E+0"),
                                scanInfo.FilterText);

                        Console.WriteLine(scanSummary);

                        Dictionary<int, Dictionary<string, string>> expectedDataThisFile;
                        if (!expectedData.TryGetValue(Path.GetFileNameWithoutExtension(dataFile.Name), out expectedDataThisFile))
                        {
                            Assert.Fail("Dataset {0} not found in dictionary expectedData", dataFile.Name);
                        }

                        Dictionary<string, string> expectedDataByType;
                        if (expectedDataThisFile.TryGetValue(scanNumber, out expectedDataByType))
                        {
                            var keySpec = maxNumberOfPeaks + "_" + centroidData;
                            string expectedDataDetails;
                            if (expectedDataByType.TryGetValue(keySpec, out expectedDataDetails))
                            {
                                Assert.AreEqual(expectedDataDetails, scanSummary.Substring(22),
                                                "Scan details mismatch, scan " + scanNumber + ", keySpec " + keySpec);
                            }
                        }
                    }
                }
            }
        }
        private static void TestReader(string rawFilePath, bool centroid = false, bool testSumming = false, int scanStart = 0, int scanEnd = 0)
        {
            try {
                if (!File.Exists(rawFilePath)) {
                    Console.WriteLine("File not found, skipping: " + rawFilePath);
                    return;
                }

                using (var oReader = new XRawFileIO(rawFilePath))
                {

                    foreach(var method in oReader.FileInfo.InstMethods) {
                        Console.WriteLine(method);
                    }

                    var iNumScans = oReader.GetNumScans();

                    var strCollisionEnergies = string.Empty;

                    ShowMethod(oReader);

                    var scanStep = 1;

                    if (scanStart < 1)
                        scanStart = 1;
                    if (scanEnd < 1) {
                        scanEnd = iNumScans;
                        scanStep = 21;
                    } else {
                        if (scanEnd < scanStart) {
                            scanEnd = scanStart;
                        }
                    }

                    for (var iScanNum = scanStart; iScanNum <= scanEnd; iScanNum += scanStep) {
                        clsScanInfo oScanInfo;

                        var bSuccess = oReader.GetScanInfo(iScanNum, out oScanInfo);
                        if (bSuccess) {
                            Console.Write("Scan " + iScanNum + " at " + oScanInfo.RetentionTime.ToString("0.00") + " minutes: " + oScanInfo.FilterText);
                            var lstCollisionEnergies = oReader.GetCollisionEnergy(iScanNum);

                            if (lstCollisionEnergies.Count == 0) {
                                strCollisionEnergies = string.Empty;
                            } else if (lstCollisionEnergies.Count >= 1) {
                                strCollisionEnergies = lstCollisionEnergies[0].ToString("0.0");

                                if (lstCollisionEnergies.Count > 1) {
                                    for (var intIndex = 1; intIndex <= lstCollisionEnergies.Count - 1; intIndex++) {
                                        strCollisionEnergies += ", " + lstCollisionEnergies[intIndex].ToString("0.0");
                                    }
                                }
                            }

                            if (string.IsNullOrEmpty(strCollisionEnergies)) {
                                Console.WriteLine();
                            } else {
                                Console.WriteLine("; CE " + strCollisionEnergies);
                            }

                            string monoMZ;
                            string chargeState;
                            string isolationWidth;

                            if (oScanInfo.TryGetScanEvent("Monoisotopic M/Z:", out monoMZ, false)) {
                                Console.WriteLine("Monoisotopic M/Z: " + monoMZ);
                            }

                            if (oScanInfo.TryGetScanEvent("Charge State", out chargeState, true))
                            {
                                Console.WriteLine("Charge State: " + chargeState);
                            }

                            if (oScanInfo.TryGetScanEvent("MS2 Isolation Width", out isolationWidth, true))
                            {
                                Console.WriteLine("MS2 Isolation Width: " + isolationWidth);
                            }

                            if (iScanNum % 50 == 0 || scanEnd - scanStart <= 50) {
                                // Get the data for scan iScanNum

                                Console.WriteLine();
                                Console.WriteLine("Spectrum for scan " + iScanNum);

                                double[] dblMzList;
                                double[] dblIntensityList;
                                var intDataCount = oReader.GetScanData(iScanNum, out dblMzList, out dblIntensityList, 0, centroid);

                                var mzDisplayStepSize = 50;
                                if (centroid) {
                                    mzDisplayStepSize = 1;
                                }

                                for (var iDataPoint = 0; iDataPoint <= dblMzList.Length - 1; iDataPoint += mzDisplayStepSize) {
                                    Console.WriteLine("  " + dblMzList[iDataPoint].ToString("0.000") + " mz   " + dblIntensityList[iDataPoint].ToString("0"));
                                }
                                Console.WriteLine();

                                const int scansToSum = 15;

                                if (iScanNum + scansToSum < iNumScans & testSumming) {
                                    // Get the data for scan iScanNum through iScanNum + 15

                                    double[,] dblMassIntensityPairs;
                                    var dataCount = oReader.GetScanDataSumScans(iScanNum, iScanNum + scansToSum, out dblMassIntensityPairs, 0, centroid);

                                    Console.WriteLine("Summed spectrum, scans " + iScanNum + " through " + (iScanNum + scansToSum));

                                    for (var iDataPoint = 0; iDataPoint <= dblMassIntensityPairs.GetLength(1) - 1; iDataPoint += 50) {
                                        Console.WriteLine("  " + dblMassIntensityPairs[0, iDataPoint].ToString("0.000") + " mz   " + dblMassIntensityPairs[1, iDataPoint].ToString("0"));
                                    }

                                    Console.WriteLine();
                                }

                                if (oScanInfo.IsFTMS) {
                                    udtFTLabelInfoType[] ftLabelData;

                                    var dataCount = oReader.GetScanLabelData(iScanNum, out ftLabelData);

                                    Console.WriteLine();
                                    Console.WriteLine("{0,12}{1,12}{2,12}{3,12}{4,12}{5,12}", "Mass", "Intensity", "Resolution", "Baseline", "Noise", "Charge");

                                    for (var iDataPoint = 0; iDataPoint <= dataCount - 1; iDataPoint += 50) {
                                        Console.WriteLine("{0,12}{1,12}{2,12}{3,12}{4,12}{5,12}", ftLabelData[iDataPoint].Mass.ToString("0.000"), ftLabelData[iDataPoint].Intensity.ToString("0"), ftLabelData[iDataPoint].Resolution.ToString("0"), ftLabelData[iDataPoint].Baseline.ToString("0.0"), ftLabelData[iDataPoint].Noise.ToString("0"), ftLabelData[iDataPoint].Charge.ToString("0"));
                                    }

                                    udtMassPrecisionInfoType[] ftPrecisionData;

                                    dataCount = oReader.GetScanPrecisionData(iScanNum, out ftPrecisionData);

                                    Console.WriteLine();
                                    Console.WriteLine("{0,12}{1,12}{2,12}{3,12}{4,12}", "Mass", "Intensity", "AccuracyMMU", "AccuracyPPM", "Resolution");

                                    for (var iDataPoint = 0; iDataPoint <= dataCount - 1; iDataPoint += 50) {
                                        Console.WriteLine("{0,12}{1,12}{2,12}{3,12}{4,12}", ftPrecisionData[iDataPoint].Mass.ToString("0.000"), ftPrecisionData[iDataPoint].Intensity.ToString("0"), ftPrecisionData[iDataPoint].AccuracyMMU.ToString("0.000"), ftPrecisionData[iDataPoint].AccuracyPPM.ToString("0.000"), ftPrecisionData[iDataPoint].Resolution.ToString("0"));
                                    }
                                }

                            }

                        }
                    }

                }

            } catch (Exception ex) {
                Console.WriteLine("Error in sub TestReader: " + ex.Message);
            }
        }