using Robotico.Graph; using Robotico.Nexus.Client.Tests.TestSupport; using Robotico.Result.Errors; using Xunit; namespace Robotico.Nexus.Client.Tests.Graph; public class NexusGraphSessionTests : IAsyncLifetime { private NexusTestHost _host = null!; private NexusClient _client = null!; private IGraphSession _session = null!; public async Task InitializeAsync() { _host = await NexusTestHost.StartAsync(); Robotico.Result.Result connected = NexusClient.Connect(_host.ConnectionUri(NexusUriSchemes.Graph)); Assert.True(connected.IsSuccess(out NexusClient? client, out _)); _client = client!; Robotico.Result.Result opened = _client.Graph.Open("session-db"); Assert.True(opened.IsSuccess(out IGraphSession? session, out _)); _session = session!; } public async Task DisposeAsync() { _session.Dispose(); _client.Dispose(); await _host.DisposeAsync(); } [Fact] public void RegisterLabel_Succeeds() { Robotico.Result.Result result = _session.RegisterLabel("Person"); Assert.True(result.IsSuccess()); } [Fact] public void RegisterLabel_Fails_WhenBlank() { Robotico.Result.Result result = _session.RegisterLabel(" "); Assert.True(result.IsError(out IError? error)); Assert.Equal(GraphErrors.InvalidArgument, error!.Code); } [Fact] public void RegisterEdgeType_Succeeds() { Robotico.Result.Result result = _session.RegisterEdgeType("WorksAt"); Assert.True(result.IsSuccess()); } [Fact] public void RegisterEdgeType_Fails_WhenBlank() { Robotico.Result.Result result = _session.RegisterEdgeType(string.Empty); Assert.True(result.IsError(out IError? error)); Assert.Equal(GraphErrors.InvalidArgument, error!.Code); } [Fact] public void UpsertVertex_ThenGetVertex_RoundTrips() { Robotico.Result.Result upserted = _session.UpsertVertex(1, ["Person"]); Assert.True(upserted.IsSuccess()); Robotico.Result.Result fetched = _session.GetVertex(1); Assert.True(fetched.IsSuccess(out GraphVertex? vertex, out _)); Assert.Equal(1ul, vertex!.VertexId); Assert.Contains("Person", vertex.Labels); } [Fact] public void UpsertVertex_Fails_WhenNoLabels() { Robotico.Result.Result result = _session.UpsertVertex(1, []); Assert.True(result.IsError(out IError? error)); Assert.Equal(GraphErrors.InvalidArgument, error!.Code); } [Fact] public void GetVertex_Fails_WhenNotFound() { Robotico.Result.Result result = _session.GetVertex(999); Assert.True(result.IsError(out IError? error)); Assert.Equal(NexusErrors.NotFound, error!.Code); } [Fact] public void DeleteVertex_Succeeds() { _session.UpsertVertex(2, ["Person"]); Robotico.Result.Result result = _session.DeleteVertex(2); Assert.True(result.IsSuccess()); Assert.True(_session.GetVertex(2).IsError(out _)); } [Fact] public void UpsertEdge_ThenGetEdge_RoundTrips() { _session.UpsertVertex(1, ["Person"]); _session.UpsertVertex(2, ["Company"]); Robotico.Result.Result upserted = _session.UpsertEdge(1, 2, "WorksAt"); Assert.True(upserted.IsSuccess()); Robotico.Result.Result fetched = _session.GetEdge(1, 2, "WorksAt"); Assert.True(fetched.IsSuccess(out GraphEdge? edge, out _)); Assert.Equal(1ul, edge!.SourceVertexId); Assert.Equal(2ul, edge.TargetVertexId); Assert.Equal("WorksAt", edge.EdgeTypeName); } [Fact] public void UpsertEdge_Fails_WhenEdgeTypeBlank() { Robotico.Result.Result result = _session.UpsertEdge(1, 2, string.Empty); Assert.True(result.IsError(out IError? error)); Assert.Equal(GraphErrors.InvalidArgument, error!.Code); } [Fact] public void DeleteEdge_Succeeds() { _session.UpsertVertex(1, ["Person"]); _session.UpsertVertex(2, ["Company"]); _session.UpsertEdge(1, 2, "WorksAt"); Robotico.Result.Result result = _session.DeleteEdge(1, 2, "WorksAt"); Assert.True(result.IsSuccess()); Assert.True(_session.GetEdge(1, 2, "WorksAt").IsError(out _)); } [Fact] public void DeleteEdge_Fails_WhenEdgeTypeBlank() { Robotico.Result.Result result = _session.DeleteEdge(1, 2, " "); Assert.True(result.IsError(out IError? error)); Assert.Equal(GraphErrors.InvalidArgument, error!.Code); } [Fact] public void GetEdge_Fails_WhenEdgeTypeBlank() { Robotico.Result.Result result = _session.GetEdge(1, 2, string.Empty); Assert.True(result.IsError(out IError? error)); Assert.Equal(GraphErrors.InvalidArgument, error!.Code); } [Fact] public void GetEdge_Fails_WhenNotFound() { Robotico.Result.Result result = _session.GetEdge(1, 2, "Missing"); Assert.True(result.IsError(out IError? error)); Assert.Equal(NexusErrors.NotFound, error!.Code); } [Fact] public void GetNeighborhood_ReturnsStartVertex() { Robotico.Result.Result result = _session.GetNeighborhood(1, maxDepth: 2, edgeTypeName: "WorksAt"); Assert.True(result.IsSuccess(out GraphNeighborhood? neighborhood, out _)); Assert.Equal(1ul, neighborhood!.StartVertexId); Assert.Contains(1ul, neighborhood.VisitOrder); } [Fact] public void GetNeighborhood_Succeeds_WithoutOptionalArguments() { Robotico.Result.Result result = _session.GetNeighborhood(1); Assert.True(result.IsSuccess()); } [Fact] public void ListVerticesByLabel_ReturnsMatchingVertices() { _session.UpsertVertex(10, ["Person"]); _session.UpsertVertex(11, ["Person"]); _session.UpsertVertex(12, ["Company"]); Robotico.Result.Result result = _session.ListVerticesByLabel("Person", skip: 0, limit: 25); Assert.True(result.IsSuccess(out GraphVertexPage? page, out _)); Assert.Equal("Person", page!.LabelName); Assert.Equal(2, page.TotalCount); } [Fact] public void ListVerticesByLabel_Fails_WhenLabelBlank() { Robotico.Result.Result result = _session.ListVerticesByLabel(string.Empty); Assert.True(result.IsError(out IError? error)); Assert.Equal(GraphErrors.InvalidArgument, error!.Code); } [Fact] public void AllOperations_Fail_AfterDispose() { _session.Dispose(); Assert.True(_session.RegisterLabel("x").IsError(out IError? e1)); Assert.Equal(NexusErrors.Disposed, e1!.Code); Assert.True(_session.RegisterEdgeType("x").IsError(out IError? e2)); Assert.Equal(NexusErrors.Disposed, e2!.Code); Assert.True(_session.UpsertVertex(1, ["A"]).IsError(out IError? e3)); Assert.Equal(NexusErrors.Disposed, e3!.Code); Assert.True(_session.DeleteVertex(1).IsError(out IError? e4)); Assert.Equal(NexusErrors.Disposed, e4!.Code); Assert.True(_session.GetVertex(1).IsError(out IError? e5)); Assert.Equal(NexusErrors.Disposed, e5!.Code); Assert.True(_session.UpsertEdge(1, 2, "x").IsError(out IError? e6)); Assert.Equal(NexusErrors.Disposed, e6!.Code); Assert.True(_session.DeleteEdge(1, 2, "x").IsError(out IError? e7)); Assert.Equal(NexusErrors.Disposed, e7!.Code); Assert.True(_session.GetEdge(1, 2, "x").IsError(out IError? e8)); Assert.Equal(NexusErrors.Disposed, e8!.Code); Assert.True(_session.GetNeighborhood(1).IsError(out IError? e9)); Assert.Equal(NexusErrors.Disposed, e9!.Code); Assert.True(_session.ListVerticesByLabel("x").IsError(out IError? e10)); Assert.Equal(NexusErrors.Disposed, e10!.Code); } }