Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions SW.Bitween.Api/Resources/Mappers/Preview.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ public Preview(RequestContext requestContext, BitweenDbContext dbContext)

public async Task<MapperPreviewResponse> Handle(MapperPreviewRequest request)
{
_requestContext.EnsureAccess(AccountRole.Admin, AccountRole.Member);

var partner = request.PartnerId.HasValue
? await _dbContext.FindAsync<Partner>(request.PartnerId.Value)
: null;
Expand Down
54 changes: 54 additions & 0 deletions SW.Bitween.UnitTests/NativeJsonMapperTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SW.Bitween.NativeAdapters;
using SW.PrimitiveTypes;
using static SW.Bitween.UnitTests.ScribanJsonTestHelper;

namespace SW.Bitween.UnitTests;

[TestClass]
public class NativeJsonMapperTests
{
[TestMethod]
public async Task NativeJsonMapper_MapsInputUsingStartupTemplate()
{
var mapper = new NativeJSONMapper();
mapper.InitializeStartupValues(new Dictionary<string, string>
{
["ScribanTemplate"] = "{ \"id\": {{ orderId | json }} }"
});

var input = new XchangeFile("{\"orderId\":\"123\"}");
var output = await mapper.Handle(input);

AssertJsonEquals("{\"id\":\"123\"}", output.Data);
}

[TestMethod]
public async Task NativeJsonMapper_WhenTemplateMissing_UsesDefaultEmptyObject()
{
var mapper = new NativeJSONMapper();
mapper.InitializeStartupValues(new Dictionary<string, string>());

var output = await mapper.Handle(new XchangeFile("{\"x\":1}"));

AssertJsonEquals("{}", output.Data);
}

[TestMethod]
public async Task NativeJsonMapper_ReturnsNewXchangeFileInstance()
{
var mapper = new NativeJSONMapper();
mapper.InitializeStartupValues(new Dictionary<string, string>
{
["ScribanTemplate"] = "{ \"x\": {{ x | json }} }"
});

var input = new XchangeFile("{\"x\":1}");
var output = await mapper.Handle(input);

Assert.AreNotSame(input, output);
AssertJsonEquals("{\"x\":1}", output.Data);
}
}
85 changes: 85 additions & 0 deletions SW.Bitween.UnitTests/RunMapperEnrichmentTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json.Linq;

namespace SW.Bitween.UnitTests;

[TestClass]
public class RunMapperEnrichmentTests
{
// Replicates the fixed parsing logic in XchangeService.RunMapper
private static JObject TryParseAsJObject(string data) =>
JToken.Parse(data) as JObject;

[TestMethod]
[Description("Receiver returns a plain JSON string — should not throw and should skip enrichment")]
public void WhenDataIsJsonString_ShouldNotThrow_AndReturnNull()
{
var data = "\"this is a plain string response from the receiver\"";

var result = TryParseAsJObject(data);

Assert.IsNull(result, "Expected null because data is a JSON string, not an object");
}

[TestMethod]
[Description("Receiver returns a JSON object — enrichment should proceed normally")]
public void WhenDataIsJsonObject_ShouldReturnJObject()
{
var data = "{\"orderId\":\"123\",\"status\":\"pending\"}";

var result = TryParseAsJObject(data);

Assert.IsNotNull(result, "Expected a JObject because data is a valid JSON object");
Assert.AreEqual("123", result["orderId"]?.ToString());
}

[TestMethod]
[Description("Receiver returns a JSON array — should not throw and should skip enrichment")]
public void WhenDataIsJsonArray_ShouldNotThrow_AndReturnNull()
{
var data = "[\"item1\",\"item2\"]";

var result = TryParseAsJObject(data);

Assert.IsNull(result, "Expected null because data is a JSON array, not an object");
}

[TestMethod]
[Description("Large JSON string payload (like the one that triggered the original error) — should not throw")]
public void WhenDataIsLargeJsonString_ShouldNotThrow_AndReturnNull()
{
// Simulate the case from the error: a JSON-encoded string with ~200k chars
var innerString = new string('x', 200_000);
var data = $"\"{innerString}\"";

JObject result = null;
var threw = false;

try
{
result = TryParseAsJObject(data);
}
catch
{
threw = true;
}

Assert.IsFalse(threw, "Should not throw for a large JSON string payload");
Assert.IsNull(result, "Expected null because data is a JSON string, not an object");
}

[TestMethod]
[Description("Enrichment is injected into a JSON object when partner properties exist")]
public void WhenDataIsJsonObject_PartnerPropertiesCanBeInjected()
{
var data = "{\"orderId\":\"123\"}";
var partnerProps = new { apiKey = "abc", region = "us-east" };

var jObj = TryParseAsJObject(data);

Assert.IsNotNull(jObj);
jObj["__partner__"] = JObject.FromObject(partnerProps);

Assert.AreEqual("abc", jObj["__partner__"]?["apiKey"]?.ToString());
}
}
Loading