Introduce a setMute protocol action and an NAudio-backed AudioControlService so the Android client can toggle the Windows render endpoint mute state over WebSocket. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
155 lines
4.9 KiB
C#
155 lines
4.9 KiB
C#
using System.Text.Json;
|
|
using WirelessTextSyncer.Windows.Models;
|
|
using WirelessTextSyncer.Windows.Services;
|
|
|
|
namespace WirelessTextSyncer.Windows.Tests;
|
|
|
|
[TestClass]
|
|
public sealed class SyncMessageTests
|
|
{
|
|
[TestMethod]
|
|
public void DeserializeAndroidInsertTextMessage()
|
|
{
|
|
var message = JsonSerializer.Deserialize<SyncMessage>(
|
|
"""{"action":"insertText","text":"hello"}""",
|
|
new JsonSerializerOptions(JsonSerializerDefaults.Web));
|
|
|
|
Assert.IsNotNull(message);
|
|
Assert.AreEqual(SyncAction.InsertText, message.Action);
|
|
Assert.AreEqual("hello", message.Text);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void DeserializeAndroidBackspaceMessage()
|
|
{
|
|
var message = JsonSerializer.Deserialize<SyncMessage>(
|
|
"""{"action":"backspace"}""",
|
|
new JsonSerializerOptions(JsonSerializerDefaults.Web));
|
|
|
|
Assert.IsNotNull(message);
|
|
Assert.AreEqual(SyncAction.Backspace, message.Action);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void DeserializeAndroidReplaceAllMessage()
|
|
{
|
|
var message = JsonSerializer.Deserialize<SyncMessage>(
|
|
"""{"action":"replaceAll","text":"final text"}""",
|
|
new JsonSerializerOptions(JsonSerializerDefaults.Web));
|
|
|
|
Assert.IsNotNull(message);
|
|
Assert.AreEqual(SyncAction.ReplaceAll, message.Action);
|
|
Assert.AreEqual("final text", message.Text);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ReplaceAllAppendsSubmittedText()
|
|
{
|
|
var keyboard = new RecordingKeyboardInjectionService();
|
|
var handler = new SyncMessageHandler(keyboard, new RecordingAudioControlService());
|
|
|
|
handler.Handle(new SyncMessage
|
|
{
|
|
Action = SyncAction.ReplaceAll,
|
|
Text = "final text"
|
|
});
|
|
|
|
CollectionAssert.AreEqual(
|
|
new[] { "insert:final text" },
|
|
keyboard.Calls);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void DeserializeAndroidSetMuteMessage()
|
|
{
|
|
var message = JsonSerializer.Deserialize<SyncMessage>(
|
|
"""{"action":"setMute","muted":true}""",
|
|
new JsonSerializerOptions(JsonSerializerDefaults.Web));
|
|
|
|
Assert.IsNotNull(message);
|
|
Assert.AreEqual(SyncAction.SetMute, message.Action);
|
|
Assert.AreEqual(true, message.Muted);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void SetMuteForwardsToAudioService()
|
|
{
|
|
var audio = new RecordingAudioControlService();
|
|
var handler = new SyncMessageHandler(new RecordingKeyboardInjectionService(), audio);
|
|
|
|
handler.Handle(new SyncMessage
|
|
{
|
|
Action = SyncAction.SetMute,
|
|
Muted = true
|
|
});
|
|
|
|
CollectionAssert.AreEqual(new[] { "mute:True" }, audio.Calls);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void DiscoveryResponseContainsServiceEndpoint()
|
|
{
|
|
using var discovery = new DiscoveryResponderService(() => "192.168.1.10", () => 8181, "Desktop-WIN11");
|
|
|
|
using var document = JsonDocument.Parse(discovery.BuildResponseJson());
|
|
var root = document.RootElement;
|
|
|
|
Assert.AreEqual("wirelessTextSyncer.service", root.GetProperty("type").GetString());
|
|
Assert.AreEqual(1, root.GetProperty("version").GetInt32());
|
|
Assert.AreEqual("Desktop-WIN11", root.GetProperty("name").GetString());
|
|
Assert.AreEqual("192.168.1.10", root.GetProperty("host").GetString());
|
|
Assert.AreEqual(8181, root.GetProperty("port").GetInt32());
|
|
}
|
|
|
|
[TestMethod]
|
|
public void WebSocketServiceInfoContainsDeviceName()
|
|
{
|
|
using var server = new WebSocketServerService(new SyncMessageHandler(new RecordingKeyboardInjectionService(), new RecordingAudioControlService()), "Desktop-WIN11");
|
|
|
|
using var document = JsonDocument.Parse(server.BuildServiceInfoJson());
|
|
var root = document.RootElement;
|
|
|
|
Assert.AreEqual("wirelessTextSyncer.service", root.GetProperty("type").GetString());
|
|
Assert.AreEqual(1, root.GetProperty("version").GetInt32());
|
|
Assert.AreEqual("Desktop-WIN11", root.GetProperty("name").GetString());
|
|
Assert.AreEqual(8181, root.GetProperty("port").GetInt32());
|
|
}
|
|
|
|
private sealed class RecordingKeyboardInjectionService : IKeyboardInjectionService
|
|
{
|
|
public List<string> Calls { get; } = [];
|
|
|
|
public void InsertText(string text)
|
|
{
|
|
Calls.Add($"insert:{text}");
|
|
}
|
|
|
|
public void ReplaceFocusedText(string text)
|
|
{
|
|
Calls.Add($"replace:{text}");
|
|
}
|
|
|
|
public void Backspace()
|
|
{
|
|
Calls.Add("backspace");
|
|
}
|
|
|
|
public void Enter()
|
|
{
|
|
Calls.Add("enter");
|
|
}
|
|
}
|
|
|
|
private sealed class RecordingAudioControlService : IAudioControlService
|
|
{
|
|
public List<string> Calls { get; } = [];
|
|
|
|
public bool IsMuted => Calls.Count > 0 && Calls[^1] == "mute:True";
|
|
|
|
public void SetMute(bool muted)
|
|
{
|
|
Calls.Add($"mute:{muted}");
|
|
}
|
|
}
|
|
}
|