Skip to content

fix(serial): handle missing COM port gracefully and surface in dialog (#524)#525

Open
tylerkron wants to merge 1 commit into
mainfrom
claude/romantic-lamport-e8a9f2
Open

fix(serial): handle missing COM port gracefully and surface in dialog (#524)#525
tylerkron wants to merge 1 commit into
mainfrom
claude/romantic-lamport-e8a9f2

Conversation

@tylerkron
Copy link
Copy Markdown
Contributor

Summary

Closes #524.

Sentry was capturing FileNotFoundException from SerialPort.Open() as an error-level event whenever a user tried to connect to a COM port that did not exist (typo in the Manual USB tab, device unplugged between discovery and click). That is a user/environmental condition, not an app bug.

The fix has three parts:

  • Classify the exception correctly. SerialStreamingDevice.Connect now catches FileNotFoundException and UnauthorizedAccessException ahead of the generic catch and logs via AppLogger.Warning instead of AppLogger.Error (the latter is the sole SentrySdk.CaptureException path).
  • Pre-validate manual-port input. ConnectManualSerialAsync now checks the entered port against SerialPort.GetPortNames() before attempting to connect and surfaces a friendly inline error inside the dialog (StatusRed text under the COM-PORT field) when the port is absent.
  • Surface late-stage failures too. After the awaited Connect, we inspect ConnectionManager.Instance.ConnectionStatus. On Error we keep the dialog open and show an in-context message — this covers the "port exists but is held by another process" case that pre-validation cannot catch and that previously vanished into a silent dialog close.

The validation message auto-clears as soon as the user edits the field.

Test plan

  • dotnet build clean (build verified locally; tests run on Windows CI per build.yaml).
  • Unit tests added for the dialog VM:
    • ConnectManualSerialCommand_WithNonexistentPort_SetsManualPortError — error is set, dialog stays open.
    • ManualPortError_ClearsWhenManualPortNameChanges — auto-clear hook fires.
    • Existing WithBlankPort test tightened to assert no error surfaces for blank input.
  • Regression test added for SerialStreamingDevice.Connect with a missing port (uses "COM250" so the FileNotFoundException path is actually exercised on Windows CI).
  • Manual: enter a bogus COM name (e.g. COMxyz) on the Manual USB tab → inline red error appears, dialog stays open, Sentry receives nothing.
  • Manual: open the device with a serial console first, then try to connect from DAQiFi → "port may be in use" message appears after the connect attempt; no Sentry event.

Notes / follow-ups (out of scope)

  • The same silent-close-on-failure pattern exists in ConnectManualWifiAsync, ConnectAsync, and ConnectSerialAsync. Worth a separate UX pass.
  • NotNullToVisibilityConverter is now registered both globally (as NotNullToVis in App.xaml) and locally in DeviceLogsView.xaml — easy consolidation later.

🤖 Generated with Claude Code

…#524)

Sentry was capturing FileNotFoundException from SerialPort.Open() as an
error event whenever a user tried to connect to a COM port that did not
exist (typo in Manual USB tab, device unplugged between discovery and
click). It is a user/environmental condition, not an app bug.

- Catch FileNotFoundException and UnauthorizedAccessException in
  SerialStreamingDevice.Connect and log via AppLogger.Warning instead of
  AppLogger.Error (the latter is the sole Sentry capture path).
- Pre-validate the manually-entered port in ConnectManualSerialAsync
  against SerialPort.GetPortNames before attempting to connect, and
  surface a friendly inline error in the dialog when the port is absent.
- After the connect attempt, check ConnectionManager.ConnectionStatus
  and keep the dialog open with an error message on failure (covers the
  "port held by another process" case that pre-validation cannot catch).
- Auto-clear the validation error as soon as the user edits the field.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@tylerkron tylerkron requested a review from a team as a code owner May 9, 2026 05:03
@qodo-code-review
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Handle missing COM ports gracefully with pre-validation and error display

🐞 Bug fix 🧪 Tests

Grey Divider

Walkthroughs

Description
• Catch FileNotFoundException and UnauthorizedAccessException separately in
  SerialStreamingDevice.Connect, logging as warnings instead of errors to prevent Sentry capture of
  user/environmental conditions
• Pre-validate manually-entered COM ports against SerialPort.GetPortNames() before connection
  attempt, displaying inline error in dialog
• Check ConnectionStatus after connect attempt and keep dialog open with error message on failure,
  covering "port in use" scenarios
• Auto-clear validation error when user edits the port name field
• Add regression test for missing port handling and validation tests for dialog behavior
Diagram
flowchart LR
  A["User enters COM port"] --> B["Pre-validate against GetPortNames"]
  B -->|Port absent| C["Display inline error, keep dialog open"]
  B -->|Port available| D["Attempt Connect"]
  D -->|FileNotFoundException/UnauthorizedAccessException| E["Log as Warning, show error message"]
  D -->|Success| F["Close dialog"]
  C -->|User edits field| G["Clear error message"]
  E -->|Keep dialog open| C
Loading

Grey Divider

File Changes

1. Daqifi.Desktop.Test/Device/DisplayIdentifierTests.cs 🧪 Tests +23/-2

Add regression test for missing port handling

• Added regression test SerialStreamingDevice_Connect_WithMissingPort_ReturnsFalseWithoutThrowing
 to verify Connect() returns false instead of throwing on nonexistent ports
• Test uses "COM250" to trigger FileNotFoundException path on Windows CI runners
• Cleaned up whitespace formatting in existing test

Daqifi.Desktop.Test/Device/DisplayIdentifierTests.cs


2. Daqifi.Desktop.Test/ViewModels/ConnectionDialogViewModelCloseTests.cs 🧪 Tests +35/-0

Add validation and error-clearing tests for manual port

• Added constant NonexistentPortName for guaranteed absent port across all CI platforms
• Enhanced ConnectManualSerialCommand_WithBlankPort_DoesNotRaiseCloseRequested to assert no error
 message surfaces for blank input
• Added ConnectManualSerialCommand_WithNonexistentPort_SetsManualPortError test verifying error is
 set and dialog stays open
• Added ManualPortError_ClearsWhenManualPortNameChanges test verifying auto-clear behavior on
 field edit

Daqifi.Desktop.Test/ViewModels/ConnectionDialogViewModelCloseTests.cs


3. Daqifi.Desktop/Device/SerialDevice/SerialStreamingDevice.cs 🐞 Bug fix +20/-1

Classify port exceptions as warnings, not errors

• Added using System.IO for FileNotFoundException handling
• Added separate catch blocks for FileNotFoundException and UnauthorizedAccessException before
 generic Exception catch
• Both specific exceptions log via AppLogger.Warning (not Error) to prevent Sentry capture
• Exceptions are classified as user/environmental conditions with descriptive messages

Daqifi.Desktop/Device/SerialDevice/SerialStreamingDevice.cs


View more (3)
4. Daqifi.Desktop/ViewModels/ConnectionDialogViewModel.cs ✨ Enhancement +66/-2

Add port pre-validation and error display to connection dialog

• Converted ManualPortName from auto-property to ObservableProperty with change notification
• Added ManualPortError ObservableProperty for validation error messages
• Implemented OnManualPortNameChanged partial method to auto-clear error when user edits port name
• Added IsPortAvailable helper method that checks SerialPort.GetPortNames() with fallback on
 enumeration failure
• Enhanced ConnectManualSerialAsync with pre-validation check and post-connect status verification
• Added user-facing error messages for missing ports and connection failures
• Added using System.IO.Ports for SerialPort access

Daqifi.Desktop/ViewModels/ConnectionDialogViewModel.cs


5. Daqifi.Desktop/App.xaml ⚙️ Configuration changes +1/-0

Register NotNullToVisibilityConverter globally

• Registered NotNullToVisibilityConverter globally as NotNullToVis resource in application
 resources
• Enables reuse across views without local registration

Daqifi.Desktop/App.xaml


6. Daqifi.Desktop/View/ConnectionDialog.xaml ✨ Enhancement +4/-0

Display inline validation error for COM port field

• Added TextBlock to display ManualPortError validation message below COM port input field
• Error text styled in red (StatusRed brush) with conditional visibility binding to NotNullToVis
 converter
• Message appears only when validation error is present, auto-hides when cleared

Daqifi.Desktop/View/ConnectionDialog.xaml


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review Bot commented May 9, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (5) 📎 Requirement gaps (0)

Context used

Grey Divider


Action required

1. Unit tests use real SerialPort 📘 Rule violation ▣ Testability
Description
New tests execute code paths that call SerialPort.Open() / SerialPort.GetPortNames(), which
depend on the host environment and can be flaky on CI or non-Windows runners. This violates the
requirement to mock external dependencies in unit tests.
Code

Daqifi.Desktop.Test/Device/DisplayIdentifierTests.cs[R93-100]

+        var device = new SerialStreamingDevice("COM250");
+
+        var result = device.Connect();
+
+        Assert.IsFalse(result,
+            "Connect() against a nonexistent port should report failure, not throw.");
+        Assert.IsFalse(device.IsConnected,
+            "Device should not be marked connected when the underlying port could not be opened.");
Evidence
PR Compliance ID 244803 requires external dependencies to be mocked in unit tests; the added tests
call SerialStreamingDevice.Connect() and ConnectManualSerialCommand, which in turn rely on the
machine's real serial-port subsystem.

Rule 244803: Mock external dependencies in unit tests
Daqifi.Desktop.Test/Device/DisplayIdentifierTests.cs[93-100]
Daqifi.Desktop.Test/ViewModels/ConnectionDialogViewModelCloseTests.cs[77-92]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New unit tests depend on real serial-port APIs (OS/hardware/environment). This can introduce flakiness and violates the requirement to mock external dependencies.

## Issue Context
- `SerialStreamingDevice_Connect_WithMissingPort_ReturnsFalseWithoutThrowing()` calls `SerialStreamingDevice.Connect()` which will ultimately attempt to open a real port.
- `ConnectManualSerialCommand_WithNonexistentPort_SetsManualPortError()` exercises `SerialPort.GetPortNames()` via the ViewModel validation.

## Fix Focus Areas
- Daqifi.Desktop.Test/Device/DisplayIdentifierTests.cs[93-101]
- Daqifi.Desktop.Test/ViewModels/ConnectionDialogViewModelCloseTests.cs[77-92]
- Daqifi.Desktop/ViewModels/ConnectionDialogViewModel.cs[273-288]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. NonexistentPortName const mis-cased 📘 Rule violation ✧ Quality
Description
The new constant NonexistentPortName is not named in SCREAMING_SNAKE_CASE as required for
constants. This reduces consistency and violates the constant naming convention.
Code

Daqifi.Desktop.Test/ViewModels/ConnectionDialogViewModelCloseTests.cs[R11-13]

+    // A name guaranteed to be absent from SerialPort.GetPortNames() on every CI runner —
+    // Windows uses COM1..COMn, macOS/Linux use /dev/tty.* paths.
+    private const string NonexistentPortName = "COM_DOES_NOT_EXIST_524";
Evidence
PR Compliance ID 244814 requires constant names to use SCREAMING_SNAKE_CASE; the added `private
const string NonexistentPortName` uses PascalCase instead.

Rule 244814: Use SCREAMING_SNAKE_CASE for constant names
Daqifi.Desktop.Test/ViewModels/ConnectionDialogViewModelCloseTests.cs[11-13]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new `const` was introduced using PascalCase (`NonexistentPortName`) but constants must be named using SCREAMING_SNAKE_CASE.

## Issue Context
This is a style/compliance requirement for constant-like values to improve consistency.

## Fix Focus Areas
- Daqifi.Desktop.Test/ViewModels/ConnectionDialogViewModelCloseTests.cs[11-13]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Caught exceptions lack stack logs 📘 Rule violation ◔ Observability
Description
New catch blocks log only ex.Message and do not include the exception object, losing stack traces
and diagnostic detail. This violates the requirement to log caught exceptions with contextual
operation details.
Code

Daqifi.Desktop/Device/SerialDevice/SerialStreamingDevice.cs[R116-132]

+        catch (FileNotFoundException ex)
+        {
+            // .NET's SerialPort.Open throws FileNotFoundException when the COM port no
+            // longer exists (device unplugged, never present, or renamed). Treat as a
+            // user/environmental condition, not an app bug — log a warning instead of
+            // capturing to Sentry.
+            AppLogger.Warning($"Cannot connect on {PortName}: port is not available ({ex.Message})");
+            CleanupConnection();
+            return false;
+        }
+        catch (UnauthorizedAccessException ex)
+        {
+            // SerialPort.Open throws UnauthorizedAccessException when another process
+            // already holds the port open. Same classification as above.
+            AppLogger.Warning($"Cannot connect on {PortName}: port is in use by another process ({ex.Message})");
+            CleanupConnection();
+            return false;
Evidence
PR Compliance ID 244826 requires logging caught exceptions with operation context and exception
details; the new handlers for FileNotFoundException and UnauthorizedAccessException log warnings
without passing/logging the exception itself (only interpolating ex.Message).

Rule 244826: Log caught exceptions with contextual operation details
Daqifi.Desktop/Device/SerialDevice/SerialStreamingDevice.cs[116-132]
Daqifi.Desktop/ViewModels/ConnectionDialogViewModel.cs[280-286]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Catching exceptions and logging only `ex.Message` drops stack traces and makes diagnosis harder.

## Issue Context
`AppLogger.Error(ex, ...)` includes exception details but also captures to Sentry; warning-level caught exceptions still need stack traces without Sentry capture.

## Fix Focus Areas
- Daqifi.Desktop/Device/SerialDevice/SerialStreamingDevice.cs[116-132]
- Daqifi.Desktop/ViewModels/ConnectionDialogViewModel.cs[280-286]
- Daqifi.Desktop.Common/Loggers/AppLogger.cs[98-119]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Sync port enumeration in async UI 📘 Rule violation ➹ Performance
Description
ConnectManualSerialAsync performs synchronous serial-port enumeration via
SerialPort.GetPortNames(), which can block the UI thread before the first await. This violates
the requirement to avoid blocking synchronous calls in UI-thread code and to use async patterns for
I/O in async paths.
Code

Daqifi.Desktop/ViewModels/ConnectionDialogViewModel.cs[R273-279]

+    private static bool IsPortAvailable(string portName)
+    {
+        try
+        {
+            return SerialPort.GetPortNames()
+                .Any(p => string.Equals(p, portName, StringComparison.OrdinalIgnoreCase));
+        }
Evidence
PR Compliance IDs 244825 and 244823 require avoiding blocking synchronous I/O on UI-thread async
code paths; IsPortAvailable() calls SerialPort.GetPortNames() synchronously and is invoked from
the async command handler.

Rule 244825: Disallow blocking synchronous calls on the UI thread
Rule 244823: Use async/await for I/O operations in async code paths
Daqifi.Desktop/ViewModels/ConnectionDialogViewModel.cs[273-279]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Synchronous `SerialPort.GetPortNames()` runs on the UI thread during an async command, risking UI hangs.

## Issue Context
There is no async `GetPortNames()` API; the typical mitigation is moving the enumeration off-thread (e.g., `Task.Run`) or relying on an already-maintained list from a background discovery service.

## Fix Focus Areas
- Daqifi.Desktop/ViewModels/ConnectionDialogViewModel.cs[235-288]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
5. Overlong lines exceed 120 📘 Rule violation ✧ Quality
Description
New/modified lines contain long string literals that exceed the 120-character maximum, reducing
readability and increasing diff noise. These lines should be wrapped or split into
concatenated/interpolated segments.
Code

Daqifi.Desktop/ViewModels/ConnectionDialogViewModel.cs[R248-267]

+            ManualPortError =
+                $"Port '{portName}' is not available. Plug in the device or check Device Manager for the correct port name.";
+            Common.Loggers.AppLogger.Instance.Warning(
+                $"Manual serial connect rejected: port '{portName}' is not present on the system.");
+            return;
+        }
+
+        ManualSerialDevice = new SerialStreamingDevice(portName);
        await ConnectionManager.Instance.Connect(ManualSerialDevice);

+        // Post-connect status check covers failures the pre-flight enumeration cannot
+        // catch — most notably "port exists but is held by another process", which
+        // SerialStreamingDevice.Connect now classifies as a Warning (no Sentry capture).
+        // Without this, the dialog would close silently and the user would have no idea
+        // the connection failed.
+        if (ConnectionManager.Instance.ConnectionStatus == DAQiFiConnectionStatus.Error)
+        {
+            ManualPortError =
+                $"Could not connect to '{portName}'. The port may be in use by another application or the device is not responding.";
+            return;
Evidence
PR Compliance ID 244820 enforces a 120-character maximum line length; the added user-facing error
strings appear on single lines and exceed the limit (including indentation).

Rule 244820: Enforce maximum line length of 120 characters
Daqifi.Desktop/ViewModels/ConnectionDialogViewModel.cs[248-267]
Daqifi.Desktop/Device/SerialDevice/SerialStreamingDevice.cs[130-130]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Some newly added lines exceed the 120-character line length limit.

## Issue Context
This mainly affects long user-facing strings and log messages; these can be wrapped using string concatenation, multiline interpolated strings, or extracted resources.

## Fix Focus Areas
- Daqifi.Desktop/ViewModels/ConnectionDialogViewModel.cs[248-267]
- Daqifi.Desktop/Device/SerialDevice/SerialStreamingDevice.cs[130-130]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 9, 2026

📊 Code Coverage Report

Summary

Summary
Generated on: 5/9/2026 - 5:05:41 AM
Coverage date: 5/9/2026 - 5:04:50 AM - 5/9/2026 - 5:05:37 AM
Parser: MultiReport (4x Cobertura)
Assemblies: 3
Classes: 119
Files: 148
Line coverage: 19.6% (1686 of 8594)
Covered lines: 1686
Uncovered lines: 6908
Coverable lines: 8594
Total lines: 26585
Branch coverage: 20.7% (592 of 2850)
Covered branches: 592
Total branches: 2850
Method coverage: Feature is only available for sponsors

Coverage

DAQiFi - 19.4%
Name Line Branch
DAQiFi 19.4% 20.8%
Daqifi.Desktop.App 5.4% 0%
Daqifi.Desktop.Channel.AbstractChannel 40.9% 27.7%
Daqifi.Desktop.Channel.AnalogChannel 58.7% 25%
Daqifi.Desktop.Channel.Channel 11.5% 0%
Daqifi.Desktop.Channel.ChannelColorManager 100% 100%
Daqifi.Desktop.Channel.DataSample 91.6%
Daqifi.Desktop.Channel.DigitalChannel 65.2% 25%
Daqifi.Desktop.Commands.CompositeCommand 0% 0%
Daqifi.Desktop.Commands.HostCommands 0%
Daqifi.Desktop.Commands.WeakEventHandlerManager 0% 0%
Daqifi.Desktop.Configuration.FirewallConfiguration 90.6% 66.6%
Daqifi.Desktop.Configuration.WindowsFirewallWrapper 64% 68.4%
Daqifi.Desktop.ConnectionManager 42.4% 39.2%
Daqifi.Desktop.Converters.BoolToActiveStatusConverter 0% 0%
Daqifi.Desktop.Converters.BoolToConnectionStatusConverter 0% 0%
Daqifi.Desktop.Converters.BoolToStatusColorConverter 0% 0%
Daqifi.Desktop.Converters.BrushColorMatchConverter 0% 0%
Daqifi.Desktop.Converters.ConnectionTypeToColorConverter 0% 0%
Daqifi.Desktop.Converters.ConnectionTypeToUsbConverter 0% 0%
Daqifi.Desktop.Converters.InvertedBoolToVisibilityConverter 0% 0%
Daqifi.Desktop.Converters.ListToStringConverter 0% 0%
Daqifi.Desktop.Converters.NotNullToVisibilityConverter 0% 0%
Daqifi.Desktop.Converters.OxyColorToBrushConverter 0% 0%
Daqifi.Desktop.Device.AbstractStreamingDevice 42.8% 38.2%
Daqifi.Desktop.Device.DeviceMessage 0%
Daqifi.Desktop.Device.Firmware.BootloaderSessionStreamingDeviceAdapter 0% 0%
Daqifi.Desktop.Device.Firmware.WifiPromptDelayProcessRunner 0% 0%
Daqifi.Desktop.Device.NativeMethods 100%
Daqifi.Desktop.Device.SerialDevice.SerialStreamingDevice 38.1% 36.7%
Daqifi.Desktop.Device.WiFiDevice.DaqifiStreamingDevice 40.9% 39.4%
Daqifi.Desktop.DialogService.DialogService 0% 0%
Daqifi.Desktop.DialogService.ServiceLocator 0% 0%
Daqifi.Desktop.DiskSpace.DiskSpaceCheckResult 100%
Daqifi.Desktop.DiskSpace.DiskSpaceEventArgs 100%
Daqifi.Desktop.DiskSpace.DiskSpaceMonitor 88.2% 86.6%
Daqifi.Desktop.DuplicateDeviceCheckResult 100%
Daqifi.Desktop.Exporter.OptimizedLoggingSessionExporter 66.5% 62.7%
Daqifi.Desktop.Exporter.SampleData 100%
Daqifi.Desktop.Helpers.BooleanConverter`1 0% 0%
Daqifi.Desktop.Helpers.BooleanToInverseBoolConverter 0% 0%
Daqifi.Desktop.Helpers.BooleanToVisibilityConverter 0%
Daqifi.Desktop.Helpers.EnumDescriptionConverter 100% 100%
Daqifi.Desktop.Helpers.IntToVisibilityConverter 0% 0%
Daqifi.Desktop.Helpers.MinMaxDownsampler 98.6% 97.9%
Daqifi.Desktop.Helpers.MyMultiValueConverter 0%
Daqifi.Desktop.Helpers.NaturalSortHelper 100% 100%
Daqifi.Desktop.Helpers.OxyPlotDarkTheme 0%
Daqifi.Desktop.Helpers.VersionHelper 98.2% 66.2%
Daqifi.Desktop.Logger.DatabaseLogger 0% 0%
Daqifi.Desktop.Logger.DatabaseMigrator 0% 0%
Daqifi.Desktop.Logger.DeviceLegendGroup 100% 100%
Daqifi.Desktop.Logger.LoggedSeriesLegendItem 0% 0%
Daqifi.Desktop.Logger.LoggingContext 100%
Daqifi.Desktop.Logger.LoggingContextDesignTimeFactory 0%
Daqifi.Desktop.Logger.LoggingManager 0% 0%
Daqifi.Desktop.Logger.LoggingSession 16% 5%
Daqifi.Desktop.Logger.PlotLogger 0% 0%
Daqifi.Desktop.Logger.SessionDeviceMetadata 80%
Daqifi.Desktop.Logger.SummaryLogger 0% 0%
Daqifi.Desktop.Logger.TimestampGapDetector 95% 83.3%
Daqifi.Desktop.Loggers.ImportOptions 0%
Daqifi.Desktop.Loggers.ImportProgress 0% 0%
Daqifi.Desktop.Loggers.SdCardSessionImporter 0% 0%
Daqifi.Desktop.MainWindow 0% 0%
Daqifi.Desktop.Migrations.AddSamplesSessionTimeIndex 0%
Daqifi.Desktop.Migrations.AddSessionDeviceMetadata 0%
Daqifi.Desktop.Migrations.AddSessionSampleCount 0%
Daqifi.Desktop.Migrations.InitialSQLiteMigration 0%
Daqifi.Desktop.Migrations.LoggingContextModelSnapshot 0%
Daqifi.Desktop.Models.AddProfileModel 0%
Daqifi.Desktop.Models.DaqifiSettings 80.5% 83.3%
Daqifi.Desktop.Models.DebugDataCollection 6.6% 0%
Daqifi.Desktop.Models.DebugDataModel 0% 0%
Daqifi.Desktop.Models.Notifications 0%
Daqifi.Desktop.Models.SdCardFile 16.6% 0%
Daqifi.Desktop.Services.WindowsPrincipalAdminChecker 0%
Daqifi.Desktop.Services.WpfMessageBoxService 0%
Daqifi.Desktop.UpdateVersion.VersionNotification 85.7% 58.3%
Daqifi.Desktop.View.ConnectionDialog 0% 0%
Daqifi.Desktop.View.DebugWindow 0% 0%
Daqifi.Desktop.View.DeviceLogsView 0% 0%
Daqifi.Desktop.View.DuplicateDeviceDialog 0% 0%
Daqifi.Desktop.View.ErrorDialog 0% 0%
Daqifi.Desktop.View.ExportDialog 0% 0%
Daqifi.Desktop.View.FirmwareDialog 0% 0%
Daqifi.Desktop.View.Flyouts.FirmwareFlyout 0% 0%
Daqifi.Desktop.View.Flyouts.LiveGraphFlyout 0% 0%
Daqifi.Desktop.View.Flyouts.NotificationsFlyout 0% 0%
Daqifi.Desktop.View.Flyouts.SummaryFlyout 0% 0%
Daqifi.Desktop.View.MigrationStatusWindow 0% 0%
Daqifi.Desktop.View.MinimapInteractionController 0% 0%
Daqifi.Desktop.View.ProfilesPane 0% 0%
Daqifi.Desktop.View.Prototype.ChannelsPanePrototype 0% 0%
Daqifi.Desktop.View.Prototype.DevicesPanePrototype 0% 0%
Daqifi.Desktop.View.Prototype.LiveGraphPane 0% 0%
Daqifi.Desktop.View.Prototype.LoggedDataPanePrototype 0% 0%
Daqifi.Desktop.View.SuccessDialog 0% 0%
Daqifi.Desktop.ViewModels.ChannelsPaneViewModel 0% 0%
Daqifi.Desktop.ViewModels.ChannelTileViewModel 0% 0%
Daqifi.Desktop.ViewModels.ConnectionDialogViewModel 38.9% 41%
Daqifi.Desktop.ViewModels.DaqifiViewModel 17.5% 10.9%
Daqifi.Desktop.ViewModels.DeviceLogsViewModel 52.5% 48%
Daqifi.Desktop.ViewModels.DevicesPaneViewModel 0% 0%
Daqifi.Desktop.ViewModels.DeviceTileViewModel 0% 0%
Daqifi.Desktop.ViewModels.DuplicateDeviceDialogViewModel 0%
Daqifi.Desktop.ViewModels.ErrorDialogViewModel 0%
Daqifi.Desktop.ViewModels.ExportDialogViewModel 0% 0%
Daqifi.Desktop.ViewModels.FirmwareDialogViewModel 0% 0%
Daqifi.Desktop.ViewModels.NewProfileChannelItem 0%
Daqifi.Desktop.ViewModels.NewProfileDeviceItem 0% 0%
Daqifi.Desktop.ViewModels.ProfilesPaneViewModel 0% 0%
Daqifi.Desktop.ViewModels.SettingsViewModel 0% 0%
Daqifi.Desktop.ViewModels.SuccessDialogViewModel 85.7%
Daqifi.Desktop.WindowViewModelMapping.IWindowViewModelMappingsContract 0%
Daqifi.Desktop.WindowViewModelMapping.WindowViewModelMappings 0%
Sentry.Generated.BuildPropertyInitializer 100%
Daqifi.Desktop.Common - 30.8%
Name Line Branch
Daqifi.Desktop.Common 30.8% 16.6%
Daqifi.Desktop.Common.Loggers.AppLogger 33.7% 16.6%
Daqifi.Desktop.Common.Loggers.NoOpLogger 0%
Daqifi.Desktop.IO - 100%
Name Line Branch
Daqifi.Desktop.IO 100% ****
Daqifi.Desktop.IO.Messages.MessageEventArgs`1 100%

Coverage report generated by ReportGeneratorView full report in build artifacts

Comment on lines +93 to +100
var device = new SerialStreamingDevice("COM250");

var result = device.Connect();

Assert.IsFalse(result,
"Connect() against a nonexistent port should report failure, not throw.");
Assert.IsFalse(device.IsConnected,
"Device should not be marked connected when the underlying port could not be opened.");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Unit tests use real serialport 📘 Rule violation ▣ Testability

New tests execute code paths that call SerialPort.Open() / SerialPort.GetPortNames(), which
depend on the host environment and can be flaky on CI or non-Windows runners. This violates the
requirement to mock external dependencies in unit tests.
Agent Prompt
## Issue description
New unit tests depend on real serial-port APIs (OS/hardware/environment). This can introduce flakiness and violates the requirement to mock external dependencies.

## Issue Context
- `SerialStreamingDevice_Connect_WithMissingPort_ReturnsFalseWithoutThrowing()` calls `SerialStreamingDevice.Connect()` which will ultimately attempt to open a real port.
- `ConnectManualSerialCommand_WithNonexistentPort_SetsManualPortError()` exercises `SerialPort.GetPortNames()` via the ViewModel validation.

## Fix Focus Areas
- Daqifi.Desktop.Test/Device/DisplayIdentifierTests.cs[93-101]
- Daqifi.Desktop.Test/ViewModels/ConnectionDialogViewModelCloseTests.cs[77-92]
- Daqifi.Desktop/ViewModels/ConnectionDialogViewModel.cs[273-288]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

System.IO.FileNotFoundException: Could not find file 'COM3'.

1 participant