dragon-iso/src/tests/TeamsISO.Engine.Tests/Domain/NdiSourceParserTests.cs
Zac Gaetano ca124540a7 fix(parser): accept 'MS Teams' brand prefix from current Teams NDI broadcasts
The new Microsoft Teams desktop client (observed against a live meeting on Teams 26106.1906.4665.7308) emits NDI source strings of the form

    WOOGLIN (MS Teams - Brendon Power)

    WOOGLIN (MS Teams - (Local))

    WOOGLIN (MS Teams - Active Speaker)

rather than the legacy 'MACHINE (Teams - ...)' shape NdiSourceParser was written to. As a result every Teams source was rejected and TeamsISO showed zero participants in real meetings.

Refactor the parser to recognize 'Teams', 'MS Teams', and (defensively) 'Microsoft Teams' as brand prefixes — longest first so 'MS Teams' isn't shadowed. Also recognize reserved suffix tokens after a dash ('Active Speaker' / 'Audio' / 'Audio Mix' / 'Screen Share') so the new active-speaker output is correctly classified as ActiveSpeaker rather than misread as a participant named 'Active Speaker'.

Tests: kept all legacy cases, added MS Teams + Microsoft Teams variants and the new dash-prefixed reserved-suffix cases. 69/69 unit tests passing; verified end-to-end against a live Teams meeting where TeamsISO.exe now shows '(Local)' and 'Brendon Power' in the Participants DataGrid.
2026-05-07 23:33:43 -04:00

58 lines
2.7 KiB
C#

using TeamsISO.Engine.Discovery;
using TeamsISO.Engine.Domain;
namespace TeamsISO.Engine.Tests.Domain;
public class NdiSourceParserTests
{
[Theory]
// ----- Legacy "Teams" brand (older Teams desktop) -----
[InlineData("WORKSTATION-01 (Teams - Jane Doe)", "WORKSTATION-01", NdiSourceKind.Participant, "Jane Doe")]
[InlineData("PROD-PC (Teams - Élise O'Connor)", "PROD-PC", NdiSourceKind.Participant, "Élise O'Connor")]
[InlineData("HOST (Teams - Smith, Bob (PM))", "HOST", NdiSourceKind.Participant, "Smith, Bob (PM)")]
// ----- Current "MS Teams" brand (the new Teams desktop client) -----
[InlineData("WOOGLIN (MS Teams - Brendon Power)", "WOOGLIN", NdiSourceKind.Participant, "Brendon Power")]
[InlineData("WOOGLIN (MS Teams - (Local))", "WOOGLIN", NdiSourceKind.Participant, "(Local)")]
[InlineData("LAB-PC (MS Teams - Smith, Bob (PM))", "LAB-PC", NdiSourceKind.Participant, "Smith, Bob (PM)")]
// ----- Defensive future-proof "Microsoft Teams" brand -----
[InlineData("WORKSTATION (Microsoft Teams - Alex Rivera)", "WORKSTATION", NdiSourceKind.Participant, "Alex Rivera")]
public void Parse_Participant_ExtractsMachineAndDisplayName(
string fullName, string expectedMachine, NdiSourceKind expectedKind, string expectedDisplay)
{
var result = NdiSourceParser.Parse(fullName);
result.Should().NotBeNull();
result!.MachineName.Should().Be(expectedMachine);
result.Kind.Should().Be(expectedKind);
result.DisplayName.Should().Be(expectedDisplay);
result.FullName.Should().Be(fullName);
}
[Theory]
// ----- Legacy "Teams" forms -----
[InlineData("HOST (Teams)", NdiSourceKind.ActiveSpeaker)]
[InlineData("HOST (Teams Audio)", NdiSourceKind.Audio)]
[InlineData("HOST (Teams Screen Share)", NdiSourceKind.ScreenShare)]
// ----- Current "MS Teams" forms (dash-prefixed reserved suffix) -----
[InlineData("WOOGLIN (MS Teams - Active Speaker)", NdiSourceKind.ActiveSpeaker)]
[InlineData("WOOGLIN (MS Teams - Audio Mix)", NdiSourceKind.Audio)]
[InlineData("WOOGLIN (MS Teams - Screen Share)", NdiSourceKind.ScreenShare)]
public void Parse_NonParticipantKinds_ClassifyCorrectly(string fullName, NdiSourceKind expectedKind)
{
var result = NdiSourceParser.Parse(fullName);
result.Should().NotBeNull();
result!.Kind.Should().Be(expectedKind);
result.DisplayName.Should().BeNull();
}
[Theory]
[InlineData("Plain NDI Source")]
[InlineData("HOST (Some Other Software)")]
[InlineData("(Teams - No Machine)")]
public void Parse_NonTeamsSource_ReturnsNull(string fullName)
{
var result = NdiSourceParser.Parse(fullName);
result.Should().BeNull();
}
}