Skip to content

Commit

Permalink
Merge branch 'main' into 440-populate-local-user-dir
Browse files Browse the repository at this point in the history
  • Loading branch information
rolfheij-sil committed Dec 22, 2023
2 parents b848a7b + c15dc2e commit d14d1cd
Show file tree
Hide file tree
Showing 39 changed files with 611 additions and 455 deletions.
28 changes: 17 additions & 11 deletions c-sharp-tests/DummyPapiClient.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using Paranext.DataProvider.MessageHandlers;
using Paranext.DataProvider.Messages;
using Paranext.DataProvider.MessageTransports;
using PtxUtils;

namespace TestParanextDataProvider
{
[ExcludeFromCodeCoverage]
internal class DummyPapiClient : PapiClient
{
private readonly Dictionary<Enum<EventType>, Func<dynamic?, Message?>> _eventHandlers = new();
private readonly Dictionary<string, Func<MessageEvent, Message?>> _eventHandlers = new();

public Stack<Message?> EventMessages { get; } = new();

Expand Down Expand Up @@ -42,28 +42,34 @@ public override Task DisconnectAsync()
return Task.CompletedTask;
}

public override Task<bool> RegisterRequestHandler(Enum<RequestType> requestType,
Func<dynamic, ResponseToRequest> requestHandler, int responseTimeoutInMs = 1000)
public override Task<bool> RegisterRequestHandler(
string requestType,
Func<JsonElement, ResponseToRequest> requestHandler,
int responseTimeoutInMs = 5000
)
{
var responder = (MessageHandlerRequestByRequestType)
_messageHandlersByMessageType[MessageType.Request];
_messageHandlersByMessageType[MessageType.REQUEST];
responder.SetHandlerForRequestType(requestType, requestHandler);

return Task.FromResult(true);
}

public override void RegisterEventHandler(Enum<EventType> eventType, Func<dynamic?, Message?> eventHandler)
public override void RegisterEventHandler(
string eventType,
Func<MessageEvent, Message?> eventHandler
)
{
_eventHandlers.Add(eventType, eventHandler);
_eventHandlers.Add(eventType, eventHandler);
}

public override void SendEvent(MessageEvent message)
{
if (!_eventHandlers.TryGetValue(message.EventType, out var handler))
return;
if (!_eventHandlers.TryGetValue(message.EventType, out var handler))
return;

Message? result = handler(message.Event);
EventMessages.Push(result);
Message? result = handler(message);
EventMessages.Push(result);
}
#endregion
}
Expand Down
8 changes: 4 additions & 4 deletions c-sharp-tests/JsonUtils/MessageConverterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ public void Deserialize_ClientConnect_StronglyTypedContentsAreCorrect()
{"type":"event","eventType":"network:onDidClientConnect","senderId":0,"event":{"clientId":3,"didReconnect":false}}
""";
var msg = DeserializeMessageEvent<MessageEventClientConnect>(messageToDecode);
Assert.That(msg.EventContents!.ClientId, Is.EqualTo(3));
Assert.That(msg.EventContents!.DidReconnect, Is.False);
Assert.That(msg.Event.ClientId, Is.EqualTo(3));
Assert.That(msg.Event.DidReconnect, Is.False);
}

[Test]
Expand All @@ -36,7 +36,7 @@ public void Deserialize_ClientDisconnect_StronglyTypedContentsAreCorrect()
{"type":"event","eventType":"network:onDidClientDisconnect","senderId":0,"event":{"clientId":123}}
""";
var msg = DeserializeMessageEvent<MessageEventClientDisconnect>(messageToDecode);
Assert.That(msg.EventContents!.ClientId, Is.EqualTo(123));
Assert.That(msg.Event.ClientId, Is.EqualTo(123));
}

[Test]
Expand All @@ -46,7 +46,7 @@ public void Deserialize_ObjectDispose_StronglyTypedContentsAreCorrect()
{"type":"event","eventType":"object:onDidDisposeNetworkObject","senderId":0,"event":"test-main"}
""";
var msg = DeserializeMessageEvent<MessageEventObjectDisposed>(messageToDecode);
Assert.That(msg.EventContents!, Is.EqualTo("test-main"));
Assert.That(msg.Event, Is.EqualTo("test-main"));
}

[Test]
Expand Down
42 changes: 42 additions & 0 deletions c-sharp-tests/JsonUtils/TupleTreeTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Paranext.DataProvider.JsonUtils;

namespace TestParanextDataProvider.JsonUtils
{
internal class TupleTreeTests
{
private static List<(string key, string val)> ConvertStringsToTuples(params string[] pairs)
{
var retVal = new List<(string key, string val)>();
if (pairs.Length % 2 != 0)
throw new ArgumentException("keys and values must be provided in pairs");
for (int i = 0; i < pairs.Length; i += 2)
{
retVal.Add((pairs[i], pairs[i + 1]));
}
return retVal;
}

[TestCase(new[] { "a", "b" }, new[] { "2" })]
[TestCase(new[] { "a", "b", "c", "d" }, new[] { "2" })]
[TestCase(new[] { "a", "b", "c", "d", "e", "f" }, new[] { "3" })]
[TestCase(new[] { "g", "h" }, new[] { "1" })]
[TestCase(new[] { "y", "z" }, new[] { "4" })]
[TestCase(new[] { "a", "b", "y", "z" }, new[] { "2", "4" })]
[TestCase(new[] { "a", "b", "c", "d", "y", "z" }, new[] { "2", "4" })]
[TestCase(new[] { "a", "b", "c", "d", "e", "f", "y", "z" }, new[] { "3", "4" })]
[TestCase(new string[0], new[] { "1" })]
public void TupleTree_FindAllResults_IsAccurate(string[] nameValuePairs, string[] expected)
{
var tree = new TupleTree<string, string, string>("1");
var values = new List<(string val1, string val2)> { ("a", "b") };
tree.Add(values, "2");
values = new List<(string val1, string val2)> { ("a", "b"), ("c", "d"), ("e", "f") };
tree.Add(values, "3");
values = new List<(string val1, string val2)> { ("y", "z") };
tree.Add(values, "4");
var results = tree.FindAllResults(ConvertStringsToTuples(nameValuePairs));
var resultsList = results.ToArray();
Assert.That(resultsList, Is.EquivalentTo(expected));
}
}
}
16 changes: 8 additions & 8 deletions c-sharp-tests/MessageHandlers/MessageHandlerEventTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Paranext.DataProvider.MessageHandlers;
using Paranext.DataProvider.Messages;
using PtxUtils;
using System.Diagnostics.CodeAnalysis;

namespace TestParanextDataProvider.MessageHandlers;
Expand Down Expand Up @@ -53,15 +52,16 @@ public void HandleMessage_SeveralHandlers_RegistrationWorks()

private static void VerifyResults(IEnumerable<Message> messages, int expectedCount)
{
Assert.That(messages.Count(), Is.EqualTo(expectedCount));
var messageList = new List<Message>(messages);
Assert.That(messageList, Has.Count.EqualTo(expectedCount));

if (expectedCount == 0)
return;

List<string> messageContents = new();
foreach (var msg in messages)
foreach (var msg in messageList)
{
messageContents.Add(((MessageEvent)msg).Event);
messageContents.Add(((MessageEvent)msg).Event!.ToString()!);
}
messageContents.Sort();
for (int i = 0; i < expectedCount; i++)
Expand All @@ -70,21 +70,21 @@ private static void VerifyResults(IEnumerable<Message> messages, int expectedCou
}
}

private static Enum<EventType> TestEventType => EventType.ObjectDispose;
private static string TestEventType => EventType.OBJECT_DISPOSE;

private static MessageEvent TestMessage => new MessageEventObjectDisposed("test");

private Message? ProcessEvent1(MessageEvent messageEvent)
private static Message ProcessEvent1(MessageEvent messageEvent)
{
return new MessageEventObjectDisposed("1");
}

private Message? ProcessEvent2(MessageEvent messageEvent)
private static Message ProcessEvent2(MessageEvent messageEvent)
{
return new MessageEventObjectDisposed("2");
}

private Message? ProcessEvent3(MessageEvent messageEvent)
private static Message ProcessEvent3(MessageEvent messageEvent)
{
return new MessageEventObjectDisposed("3");
}
Expand Down
100 changes: 73 additions & 27 deletions c-sharp-tests/PapiTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Text.Json.Nodes;
using System.Xml.Linq;
using Paratext.Data;
using PtxUtils;
using Paranext.DataProvider.Messages;
using System.Web;
using System.Diagnostics.CodeAnalysis;
Expand Down Expand Up @@ -34,8 +33,9 @@ public virtual void TestSetup()
[TearDown]
public virtual void TestTearDown()
{
List<ScrText> projects =
ScrTextCollection.ScrTexts(IncludeProjects.Everything).ToList();
List<ScrText> projects = ScrTextCollection
.ScrTexts(IncludeProjects.Everything)
.ToList();

foreach (ScrText project in projects)
ScrTextCollection.Remove(project, false);
Expand All @@ -48,7 +48,9 @@ protected DummyPapiClient Client
get
{
if (_client == null)
throw new InvalidOperationException("Can not access Client before test setup is run");
throw new InvalidOperationException(
"Can not access Client before test setup is run"
);
return _client;
}
}
Expand All @@ -58,7 +60,9 @@ protected DummyLocalParatextProjects ParatextProjects
get
{
if (_projects == null)
throw new InvalidOperationException("Can not access Projects before test setup is run");
throw new InvalidOperationException(
"Can not access Projects before test setup is run"
);
return _projects;
}
}
Expand Down Expand Up @@ -87,7 +91,11 @@ protected static ProjectDetails CreateProjectDetails(ScrText scrText)
/// Creates fake project details to fake the existence of a project
/// </summary>
/// <seealso cref="DummyLocalParatextProjects.FakeAddProject"/>
protected static ProjectDetails CreateProjectDetails(string id, string name, string projectType = "")
protected static ProjectDetails CreateProjectDetails(
string id,
string name,
string projectType = ""
)
{
ProjectMetadata metadata = new(id, name, "ParatextFolders", projectType);
return new ProjectDetails(metadata, "testDirectoryThatDoesNotExist");
Expand All @@ -98,24 +106,31 @@ protected static ProjectDetails CreateProjectDetails(string id, string name, str
/// </summary>
protected static JsonNode CreateVerseRefNode(int bookNum, int chapterNum, int verseNum)
{
return JsonNode.Parse("{ \"versification\":\"English\", " +
$"\"_bookNum\":{bookNum}, \"_chapterNum\":{chapterNum}, \"_verseNum\":{verseNum} }}")!;
return JsonNode.Parse(
"{ \"versification\":\"English\", "
+ $"\"_bookNum\":{bookNum}, \"_chapterNum\":{chapterNum}, \"_verseNum\":{verseNum} }}"
)!;
}

/// <summary>
/// Creates a JSON string node with the specified data
/// </summary>
protected static JsonNode CreateJsonString(string data)
{
JsonNode node = JsonNode.Parse($"{{ \"data\":\"{HttpUtility.JavaScriptStringEncode(data)}\" }}")!;
JsonNode node = JsonNode.Parse(
$"{{ \"data\":\"{HttpUtility.JavaScriptStringEncode(data)}\" }}"
)!;
return node.Root["data"]!;
}

/// <summary>
/// Replicates the creation of the JsonElement that is given to requests when
/// coming from the server.
/// </summary>
protected static JsonElement CreateRequestMessage(string function, params object[] parameters)
protected static JsonElement CreateRequestMessage(
string function,
params object[] parameters
)
{
StringBuilder jsonBldr = new StringBuilder();
jsonBldr.Append("{ \"value\":[");
Expand All @@ -132,7 +147,10 @@ protected static JsonElement CreateRequestMessage(string function, params object
switch (param)
{
case string str:
jsonBldr.Append("\"").Append(HttpUtility.JavaScriptStringEncode(str)).Append("\"");
jsonBldr
.Append("\"")
.Append(HttpUtility.JavaScriptStringEncode(str))
.Append("\"");
break;
case JsonNode node:
jsonBldr.Append(node.ToJsonString());
Expand All @@ -153,13 +171,19 @@ protected static JsonElement CreateRequestMessage(string function, params object
/// Creates a Data Scope node that is given to requests when
/// coming from the server.
/// </summary>
protected static JsonNode CreateDataScope(string extensionName, string dataQualifier, string? dataType = null)
protected static JsonNode CreateDataScope(
string extensionName,
string dataQualifier,
string? dataType = null
)
{
// NOTE: projectId and projectName are usually automatically supplied

return JsonNode.Parse($"{{ \"extensionName\":\"{extensionName}\", " +
$"\"dataQualifier\":\"{dataQualifier}\" }}" +
(dataType != null ? $"\"dataType\":\"{dataType}\"" : ""))!;
return JsonNode.Parse(
$"{{ \"extensionName\":\"{extensionName}\", "
+ $"\"dataQualifier\":\"{dataQualifier}\" }}"
+ (dataType != null ? $"\"dataType\":\"{dataType}\"" : "")
)!;
}
#endregion

Expand All @@ -168,7 +192,12 @@ protected static JsonNode CreateDataScope(string extensionName, string dataQuali
/// Asserts that the two snippets of USFM are the same. This function normalizes both snippets
/// to ensure maximum compatibility between them.
/// </summary>
protected static void VerifyUsfmSame(string usfm1, string usfm2, ScrText scrText, int bookNum)
protected static void VerifyUsfmSame(
string usfm1,
string usfm2,
ScrText scrText,
int bookNum
)
{
usfm1 = UsfmToken.NormalizeUsfm(scrText, bookNum, usfm1);
usfm2 = UsfmToken.NormalizeUsfm(scrText, bookNum, usfm2);
Expand All @@ -190,38 +219,55 @@ protected static void VerifyUsxSame(string usx1, string usx2)
using (TextReader reader2 = new StringReader(usx2))
doc2 = XDocument.Load(reader2);

Assert.That(doc1.Root!.ToString().Replace("\r", "").Replace("\n", ""),
Is.EqualTo(doc2.Root!.ToString().Replace("\r", "").Replace("\n", "")));
Assert.That(
doc1.Root!.ToString().Replace("\r", "").Replace("\n", ""),
Is.EqualTo(doc2.Root!.ToString().Replace("\r", "").Replace("\n", ""))
);
}

/// <summary>
/// Verifies the contents of a server response message
/// </summary>
protected static void VerifyResponse(Message message, string? expectedErrorMessage,
Enum<RequestType> expectedResponseType,
int expectedRequestId, object? expectedContents)
protected static void VerifyResponse(
Message message,
string? expectedErrorMessage,
string expectedResponseType,
int expectedRequestId,
object? expectedContents
)
{
Assert.Multiple(() =>
{
VerifyResponseExceptContents(message, expectedErrorMessage, expectedResponseType, expectedRequestId);
VerifyResponseExceptContents(
message,
expectedErrorMessage,
expectedResponseType,
expectedRequestId
);
Assert.That(((MessageResponse)message).Contents, Is.EqualTo(expectedContents));
});
}

/// <summary>
/// Verifies the contents of a server response message ignoring the contents
/// </summary>
protected static void VerifyResponseExceptContents(Message message, string? expectedErrorMessage,
Enum<RequestType> expectedResponseType,
int expectedRequestId)
protected static void VerifyResponseExceptContents(
Message message,
string? expectedErrorMessage,
string expectedResponseType,
int expectedRequestId
)
{
Assert.Multiple(() =>
{
Assert.That(message.Type, Is.EqualTo(MessageType.Response));
Assert.That(message.Type, Is.EqualTo(MessageType.RESPONSE));

MessageResponse response = (MessageResponse)message;
Assert.That(response.ErrorMessage ?? "", Does.Contain(expectedErrorMessage ?? ""));
Assert.That(response.Success, Is.EqualTo(string.IsNullOrEmpty(expectedErrorMessage)));
Assert.That(
response.Success,
Is.EqualTo(string.IsNullOrEmpty(expectedErrorMessage))
);
Assert.That(response.RequestType, Is.EqualTo(expectedResponseType));
Assert.That(response.RequestId, Is.EqualTo(expectedRequestId));
});
Expand Down
Loading

0 comments on commit d14d1cd

Please sign in to comment.