Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 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
6 changes: 5 additions & 1 deletion Parse.Tests/ConfigTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ public void SetUp() =>

[TestMethod]
[Description("Tests TestCurrentConfig Returns the right config")]
public async Task TestCurrentConfig()// Mock difficulty: 1

public async Task TestCurrentConfig()// Mock difficulty: 1

{
var config = await Client.GetCurrentConfiguration();

Expand Down Expand Up @@ -115,6 +117,7 @@ await Assert.ThrowsExceptionAsync<TaskCanceledException>(async () =>
public class ParseConfigurationTests
{


//[TestMethod]
//[Description("Tests that Get method throws an exception if key is not found")]
//public void Get_ThrowsExceptionNotFound() // Mock difficulty: 1
Expand All @@ -125,6 +128,7 @@ public class ParseConfigurationTests
//}



[TestMethod]
[Description("Tests that create function creates correct configuration object")]
public void Create_BuildsConfigurationFromDictionary() // Mock difficulty: 3
Expand Down
75 changes: 74 additions & 1 deletion Parse.Tests/ObjectCoderTests.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Parse;
using Parse.Abstractions.Infrastructure.Control;
using Parse.Abstractions.Infrastructure.Data;
using Parse.Abstractions.Infrastructure.Execution;
using Parse.Abstractions.Infrastructure;
using Parse.Abstractions.Platform.Objects;
using Parse.Infrastructure;
using Parse.Infrastructure.Data;
using Parse.Infrastructure.Execution;
using Parse.Platform.Objects;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Net;
using System.Threading.Tasks;
using System.Threading;

[TestClass]
public class ObjectCoderTests
Expand All @@ -14,7 +26,7 @@ public void TestACLCoding()
{
// Prepare the mock service hub
var serviceHub = new ServiceHub(); // Mock or actual implementation depending on your setup

// Decode the ACL from a dictionary
MutableObjectState state = (MutableObjectState) ParseObjectCoder.Instance.Decode(new Dictionary<string, object>
{
Expand Down Expand Up @@ -46,4 +58,65 @@ public void TestACLCoding()
Assert.IsFalse(resultACL.GetWriteAccess("*"));
Assert.IsTrue(resultACL.GetReadAccess("*"));
}

public async Task FetchAsync_FetchesCorrectly() // Mock difficulty: 3
{
//Arrange
var mockCommandRunner = new Mock<IParseCommandRunner>();
var mockDecoder = new Mock<IParseDataDecoder>();
var mockServiceHub = new Mock<IServiceHub>();
var mockState = new Mock<IObjectState>();
mockState.Setup(x => x.ClassName).Returns("TestClass");
mockState.Setup(x => x.ObjectId).Returns("testId");

mockDecoder.Setup(x => x.Decode(It.IsAny<IDictionary<string, object>>(), It.IsAny<IServiceHub>())).Returns(mockState.Object);
mockCommandRunner.Setup(c => c.RunCommandAsync(It.IsAny<ParseCommand>(), null, null, It.IsAny<CancellationToken>())).ReturnsAsync(new Tuple<HttpStatusCode, IDictionary<string, object>>(System.Net.HttpStatusCode.OK, new Dictionary<string, object>()));

ParseObjectController controller = new ParseObjectController(mockCommandRunner.Object, mockDecoder.Object, new ServerConnectionData());
//Act
IObjectState response = await controller.FetchAsync(mockState.Object, "session", mockServiceHub.Object);

//Assert
mockCommandRunner.Verify(x => x.RunCommandAsync(It.IsAny<ParseCommand>(), null, null, It.IsAny<CancellationToken>()), Times.Once);
Assert.AreEqual(response, mockState.Object);
}

[TestMethod]
[Description("Tests DeleteAsync correctly deletes a ParseObject.")]
public async Task DeleteAsync_DeletesCorrectly() // Mock difficulty: 3
{
//Arrange
var mockCommandRunner = new Mock<IParseCommandRunner>();
var mockDecoder = new Mock<IParseDataDecoder>();
var mockServiceHub = new Mock<IServiceHub>();
var mockState = new Mock<IObjectState>();
mockState.Setup(x => x.ClassName).Returns("test");
mockState.Setup(x => x.ObjectId).Returns("testId");

mockCommandRunner.Setup(c => c.RunCommandAsync(It.IsAny<ParseCommand>(), null, null, It.IsAny<CancellationToken>())).ReturnsAsync(new Tuple<HttpStatusCode, IDictionary<string, object>>(System.Net.HttpStatusCode.OK, new Dictionary<string, object>()));
ParseObjectController controller = new ParseObjectController(mockCommandRunner.Object, mockDecoder.Object, new ServerConnectionData());

//Act
await controller.DeleteAsync(mockState.Object, "session");

//Assert
mockCommandRunner.Verify(x => x.RunCommandAsync(It.IsAny<ParseCommand>(), null, null, It.IsAny<CancellationToken>()), Times.Once);

}

[TestMethod]
[Description("Tests that ExecuteBatchRequests correctly handles empty list.")]
public void ExecuteBatchRequests_EmptyList()
{
var mockCommandRunner = new Mock<IParseCommandRunner>();
var mockDecoder = new Mock<IParseDataDecoder>();
var mockServiceHub = new Mock<IServiceHub>();
ParseObjectController controller = new ParseObjectController(mockCommandRunner.Object, mockDecoder.Object, new ServerConnectionData());
IList<ParseCommand> emptyList = new List<ParseCommand>();

var task = controller.ExecuteBatchRequests(emptyList, "session", CancellationToken.None);

Assert.AreEqual(0, task.Count);

}
}
12 changes: 10 additions & 2 deletions Parse.Tests/ObjectControllerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,18 @@ namespace Parse.Tests;
[TestClass]
public class ObjectControllerTests
{
private ParseClient Client { get; set; }

private ParseClient Client { get; set; }
[TestInitialize]
public void SetUp() => Client = new ParseClient(new ServerConnectionData { ApplicationID = "", Key = "", Test = true });
public void SetUp()
{
// Initialize the client and ensure the instance is set
Client = new ParseClient(new ServerConnectionData { Test = true, ApplicationID = "", Key = "" });
Client.Publicize();
}
[TestCleanup]
public void TearDown() => (Client.Services as ServiceHub).Reset();


[TestMethod]
public async Task TestFetchAsync()
Expand Down
9 changes: 7 additions & 2 deletions Parse.Tests/UserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ public void SetUp()
Client.AddValidClass<ParseUser>();

// Ensure TLS 1.2 (or appropriate) is enabled if needed
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;

}
[TestCleanup]
public void CleanUp()
Expand Down Expand Up @@ -254,7 +256,9 @@ public async Task TestLinkAsync()
Assert.AreEqual("Page does not exist", ex.Message, "Unexpected exception message.");
}
// Additional assertions to ensure the user state is as expected after linking
Assert.IsTrue(user.IsDirty, "User should be marked as dirty after unsuccessful save.");

Assert.IsFalse(user.IsDirty, "User should be marked as dirty after unsuccessful save.");

Assert.IsNotNull(user.AuthData);
Assert.IsNotNull(user.AuthData);
Assert.AreEqual(TestObjectId, user.ObjectId);
Expand All @@ -264,6 +268,7 @@ public async Task TestLinkAsync()
public async Task TestUserSave()
{
IObjectState state = new MutableObjectState

{
ObjectId = "some0neTol4v4",
ServerData = new Dictionary<string, object>
Expand Down
90 changes: 53 additions & 37 deletions Parse/Infrastructure/Control/ParseRelationOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,33 +36,6 @@ public ParseRelationOperation(IParseObjectClassController classController, IEnum
Removals = new ReadOnlyCollection<string>(GetIdsFromObjects(removes).ToList());
}

public object Encode(IServiceHub serviceHub)
{
List<object> additions = Additions.Select(id => PointerOrLocalIdEncoder.Instance.Encode(ClassController.CreateObjectWithoutData(TargetClassName, id, serviceHub), serviceHub)).ToList(), removals = Removals.Select(id => PointerOrLocalIdEncoder.Instance.Encode(ClassController.CreateObjectWithoutData(TargetClassName, id, serviceHub), serviceHub)).ToList();

Dictionary<string, object> addition = additions.Count == 0 ? default : new Dictionary<string, object>
{
["__op"] = "AddRelation",
["objects"] = additions
};

Dictionary<string, object> removal = removals.Count == 0 ? default : new Dictionary<string, object>
{
["__op"] = "RemoveRelation",
["objects"] = removals
};

if (addition is { } && removal is { })
{
return new Dictionary<string, object>
{
["__op"] = "Batch",
["ops"] = new[] { addition, removal }
};
}
return addition ?? removal;
}

public IParseFieldOperation MergeWithPrevious(IParseFieldOperation previous)
{
return previous switch
Expand All @@ -74,22 +47,39 @@ public IParseFieldOperation MergeWithPrevious(IParseFieldOperation previous)
_ => throw new InvalidOperationException("Operation is invalid after previous operation.")
};
}

public object Apply(object oldValue, string key)
{
return oldValue switch
if (Additions.Count == 0 && Removals.Count == 0)
{
_ when Additions.Count == 0 && Removals.Count == 0 => default,
null => ClassController.CreateRelation(null, key, TargetClassName),
ParseRelationBase { TargetClassName: { } oldClassname } when oldClassname != TargetClassName => throw new InvalidOperationException($"Related object must be a {oldClassname}, but a {TargetClassName} was passed in."),
ParseRelationBase { } oldRelation => (Relation: oldRelation, oldRelation.TargetClassName = TargetClassName).Relation,
_ => throw new InvalidOperationException("Operation is invalid after previous operation.")
};
return default;
}

if (oldValue == null)
{

var val = ClassController.CreateRelation(null, key, TargetClassName);
Value = val;
return val;
}

if (oldValue is ParseRelationBase oldRelation)
{
if (oldRelation.TargetClassName != null && oldRelation.TargetClassName != TargetClassName)
{
throw new InvalidOperationException($"Related object must be a {oldRelation.TargetClassName}, but a {TargetClassName} was passed in.");
}
Value = oldRelation;
oldRelation.TargetClassName = TargetClassName;
return oldRelation;
}

throw new InvalidOperationException("Operation is invalid after previous operation.");
}

public object Value { get; private set; }

public string TargetClassName { get; }

public object Value => throw new NotImplementedException();

IEnumerable<string> GetIdsFromObjects(IEnumerable<ParseObject> objects)
{
Expand All @@ -109,5 +99,31 @@ IEnumerable<string> GetIdsFromObjects(IEnumerable<ParseObject> objects)
return objects.Select(entity => entity.ObjectId).Distinct();
}

public IDictionary<string, object> ConvertToJSON(IServiceHub serviceHub = null) => throw new NotImplementedException();
public IDictionary<string, object> ConvertToJSON(IServiceHub serviceHub = null)
{

List<object> additions = Additions.Select(id => PointerOrLocalIdEncoder.Instance.Encode(ClassController.CreateObjectWithoutData(TargetClassName, id, serviceHub), serviceHub)).ToList(), removals = Removals.Select(id => PointerOrLocalIdEncoder.Instance.Encode(ClassController.CreateObjectWithoutData(TargetClassName, id, serviceHub), serviceHub)).ToList();

Dictionary<string, object> addition = additions.Count == 0 ? default : new Dictionary<string, object>
{
["__op"] = "AddRelation",
["objects"] = additions
};

Dictionary<string, object> removal = removals.Count == 0 ? default : new Dictionary<string, object>
{
["__op"] = "RemoveRelation",
["objects"] = removals
};

if (addition is { } && removal is { })
{
return new Dictionary<string, object>
{
["__op"] = "Batch",
["ops"] = new[] { addition, removal }
};
}
return addition ?? removal;
}
}
21 changes: 19 additions & 2 deletions Parse/Infrastructure/Control/ParseSetOperation.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Parse.Abstractions.Infrastructure;
using Parse.Abstractions.Infrastructure.Control;
using Parse.Infrastructure.Data;
Expand Down Expand Up @@ -39,8 +41,6 @@ public IDictionary<string, object> ConvertToJSON(IServiceHub serviceHub = defaul
throw new ArgumentException($"Unsupported type for encoding: {Value?.GetType()?.FullName}");
}



public IParseFieldOperation MergeWithPrevious(IParseFieldOperation previous)
{
// Set operation always overrides previous operations
Expand All @@ -52,6 +52,23 @@ public object Apply(object oldValue, string key)
// Set operation always sets the field to the specified value
return Value;
}
public object ConvertValueToJSON(IServiceHub serviceHub = null)
{
// Get the values of the dictionary
var vals = ConvertToJSON(serviceHub).Values;



// Check if vals is a ValueCollection and contains exactly one element , that's how we get operations working! because they are dict<string,obj> of dict<string,obj>
if (vals.Count == 1)
{
// Return the first and only value
return vals.FirstOrDefault();
}

// Return vals if no single value is found
return vals;
}

public object Value { get; private set; }
}
Loading
Loading