Skip to content

Commit 29d3910

Browse files
committed
Added additional tests
1 parent c92434e commit 29d3910

1 file changed

Lines changed: 93 additions & 3 deletions

File tree

mzLib/Test/FileReadingTests/SpectraFileReading/TestBruker.cs

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
using System.Diagnostics;
2-
using System.IO;
1+
using System.IO;
32
using System.Linq;
3+
using System;
4+
using System.Data.SQLite;
45
using MassSpectrometry;
5-
using NUnit;
66
using NUnit.Framework;
77
using Readers;
88

@@ -302,5 +302,95 @@ public void TestRetentionTimeConvertedToMinutes()
302302
Assert.That(brukerData.Scans[i].RetentionTime, Is.EqualTo(expectedSeconds[i] / 60.0).Within(1e-4));
303303
}
304304
}
305+
306+
// Copies a .d fixture to a fresh temp directory and runs the supplied SQL against the copy's
307+
// analysis.sqlite cache. Lets a test stand up a Bruker file whose precursor-variable tables differ
308+
// from the three committed fixtures (all of which record charge state 0 and carry both tables),
309+
// without checking in another multi-megabyte .d folder.
310+
private static string CopyFixtureAndEditSqlite(string fixtureName, string sql)
311+
{
312+
string source = Path.Combine(TestContext.CurrentContext.TestDirectory, "DataFiles", fixtureName);
313+
string destination = Path.Combine(Path.GetTempPath(), "mzLibBrukerTest_" + Guid.NewGuid().ToString("N"), fixtureName);
314+
315+
foreach (string directory in Directory.GetDirectories(source, "*", SearchOption.AllDirectories))
316+
Directory.CreateDirectory(directory.Replace(source, destination));
317+
Directory.CreateDirectory(destination);
318+
foreach (string file in Directory.GetFiles(source, "*", SearchOption.AllDirectories))
319+
File.Copy(file, file.Replace(source, destination), true);
320+
321+
using var connection = new SQLiteConnection("DataSource=" + Path.Combine(destination, "analysis.sqlite"));
322+
connection.Open();
323+
using var command = new SQLiteCommand(sql, connection);
324+
command.ExecuteNonQuery();
325+
return destination;
326+
}
327+
328+
// The reader treats the (Per)SpectrumVariables tables as optional: older/unusual acquisitions may not
329+
// have them, and the reader is written to degrade gracefully (no isolation width) rather than throw.
330+
// Nothing exercised that fallback -- all three fixtures carry both tables -- so a typo in a table name,
331+
// or an exception escaping the SQLite handling, would have shipped as a hard crash on those files.
332+
// Dropping each table in turn from a temp copy proves the file still loads, with the peak data and
333+
// precursor m/z intact and IsolationWidth simply absent.
334+
[Test]
335+
[TestCase("SupportedVariables")] // variable-id lookup fails -> no precursor variables at all
336+
[TestCase("PerSpectrumVariables")] // ids resolve, but the per-spectrum values are unavailable
337+
public void TestPrecursorVariableTablesAreOptional(string tableToDrop)
338+
{
339+
string path = CopyFixtureAndEditSqlite("centroid_1x_MS1_4x_autoMS2.d", "DROP TABLE " + tableToDrop);
340+
341+
MsDataFile brukerData = null;
342+
Assert.DoesNotThrow(() => brukerData = MsDataFileReader.GetDataFile(path).LoadAllStaticData(),
343+
$"reader threw when {tableToDrop} was absent instead of falling back");
344+
345+
// The file still reads: same scan count, same spectra, same precursor selection as the intact fixture.
346+
Assert.That(brukerData.NumSpectra, Is.EqualTo(5));
347+
Assert.That(brukerData.Scans[1].MsnOrder, Is.EqualTo(2));
348+
Assert.That(brukerData.Scans[1].SelectedIonMZ, Is.EqualTo(721.86865).Within(0.001));
349+
Assert.That(brukerData.Scans[1].MassSpectrum.XArray, Is.Not.Empty);
350+
// Only the precursor variables are lost, and they are lost as null rather than as a bogus zero.
351+
Assert.That(brukerData.Scans[1].IsolationWidth, Is.Null);
352+
Assert.That(brukerData.Scans[1].IsolationRange, Is.Null);
353+
Assert.That(brukerData.Scans[1].SelectedIonChargeStateGuess, Is.Null);
354+
355+
// The dynamic path resolves the variables separately, so it needs its own fallback.
356+
var dynamicReader = MsDataFileReader.GetDataFile(path);
357+
dynamicReader.InitiateDynamicConnection();
358+
MsDataScan scan = null;
359+
Assert.DoesNotThrow(() => scan = dynamicReader.GetOneBasedScanFromDynamicConnection(2),
360+
$"dynamic connection threw when {tableToDrop} was absent");
361+
Assert.That(scan.SelectedIonMZ, Is.EqualTo(721.86865).Within(0.001));
362+
Assert.That(scan.IsolationWidth, Is.Null);
363+
dynamicReader.CloseDynamicConnection();
364+
}
365+
366+
// A precursor charge read from the file is handed to search engines as the charge to deconvolute at,
367+
// so getting it wrong silently mis-assigns every precursor mass in the run. Every committed fixture
368+
// records MSMS_PreCursorChargeState = 0, so the branch that surfaces a real charge never ran in any
369+
// test; only the "0 -> null" sentinel path did. Writing a real charge into a temp copy covers both:
370+
// the charge is surfaced as-is on the scan it belongs to, and a 0 on another scan stays null rather
371+
// than being reported as a charge of 0 (which would be an invalid charge state downstream).
372+
[Test]
373+
public void TestPrecursorChargeStateIsReadFromPerSpectrumVariables()
374+
{
375+
// Scan 2 gets a real charge of 3; scans 3-5 keep Bruker's 0 = "could not determine".
376+
string path = CopyFixtureAndEditSqlite("centroid_1x_MS1_4x_autoMS2.d",
377+
@"UPDATE PerSpectrumVariables SET Value = 3
378+
WHERE Spectrum = 2
379+
AND Variable = (SELECT Variable FROM SupportedVariables
380+
WHERE PermanentName = 'MSMS_PreCursorChargeState')");
381+
382+
MsDataFile brukerData = MsDataFileReader.GetDataFile(path).LoadAllStaticData();
383+
384+
Assert.That(brukerData.Scans[1].SelectedIonChargeStateGuess, Is.EqualTo(3));
385+
Assert.That(brukerData.Scans[2].SelectedIonChargeStateGuess, Is.Null,
386+
"a recorded charge of 0 means 'undetermined' and must not be surfaced as a charge of 0");
387+
388+
// The dynamic path builds the scan through a different query and must agree.
389+
var dynamicReader = MsDataFileReader.GetDataFile(path);
390+
dynamicReader.InitiateDynamicConnection();
391+
Assert.That(dynamicReader.GetOneBasedScanFromDynamicConnection(2).SelectedIonChargeStateGuess,
392+
Is.EqualTo(3));
393+
dynamicReader.CloseDynamicConnection();
394+
}
305395
}
306396
}

0 commit comments

Comments
 (0)