Skip to content

Commit 24e7d53

Browse files
authored
feat: Support for JSON-LD references (#28)
1 parent ee71319 commit 24e7d53

21 files changed

Lines changed: 550 additions & 46 deletions

OpenActive.NET.Test/BetaTest.cs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using Newtonsoft.Json;
2+
using OpenActive.NET;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using Xunit;
7+
using Xunit.Abstractions;
8+
9+
namespace OpenActive.NET.Test
10+
{
11+
12+
public class BetaTest
13+
{
14+
private readonly ITestOutputHelper output;
15+
16+
public BetaTest(ITestOutputHelper output)
17+
{
18+
this.output = output;
19+
}
20+
21+
private readonly string jsonOpportunity =
22+
"{\"@context\":[\"https://openactive.io/\",\"https://openactive.io/ns-beta\"],\"@type\":\"SessionSeries\",\"beta:affiliatedLocation\":{" +
23+
"\"@type\":\"Place\"," +
24+
"\"name\":\"Santa Clara City Library, Central Park Library\"" +
25+
"}}";
26+
27+
private readonly SessionSeries opportunity = new OpenActive.NET.SessionSeries()
28+
{
29+
AffiliatedLocation = new Place {
30+
Name = "Santa Clara City Library, Central Park Library"
31+
}
32+
};
33+
34+
[Fact]
35+
public void BetaOpportunity_Deserialize() {
36+
var decode = OpenActiveSerializer.Deserialize<SessionSeries>(jsonOpportunity);
37+
Assert.NotNull(decode);
38+
Assert.NotNull(decode.AffiliatedLocation);
39+
Assert.Equal("Santa Clara City Library, Central Park Library", decode.AffiliatedLocation.Name);
40+
}
41+
42+
[Fact]
43+
public void BetaOpportunity_EncodeDecode()
44+
{
45+
var decode = OpenActiveSerializer.Deserialize<SessionSeries>(jsonOpportunity);
46+
var encode = OpenActiveSerializer.Serialize(decode);
47+
48+
output.WriteLine(jsonOpportunity);
49+
output.WriteLine(encode);
50+
Assert.Equal(jsonOpportunity, encode);
51+
}
52+
53+
[Fact]
54+
public void BetaOpportunity_ToString_ReturnsExpectedJsonLd()
55+
{
56+
output.WriteLine(this.opportunity.ToString());
57+
Assert.Equal(this.jsonOpportunity, this.opportunity.ToString());
58+
}
59+
60+
[Fact]
61+
public void BetaOpportunity_Serialize()
62+
{
63+
var encode = OpenActiveSerializer.Serialize(this.opportunity);
64+
output.WriteLine(encode);
65+
Assert.Equal(this.jsonOpportunity, encode);
66+
}
67+
}
68+
}

OpenActive.NET.Test/EventTest.cs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,13 @@ public EventTest(ITestOutputHelper output)
7676
Organizer = NullPerson,
7777
AttendeeInstructions = "Ensure you bring trainers and a bottle of water.",
7878
MeetingPoint = "",
79-
AccessibilityInformation = NullString
79+
AccessibilityInformation = NullString,
80+
Leader = new List<Person> {
81+
new Person
82+
{
83+
SameAs = new List<Uri> { new Uri("https://www.twitter.com/SportsUnlimited"), new Uri("https://www.facebook.com/SportsUnlimited") }
84+
}
85+
}
8086
};
8187

8288
private readonly string json =
@@ -108,6 +114,12 @@ public EventTest(ITestOutputHelper output)
108114
"\"url\":\"http://www.example.com/event_image/12345\"" +
109115
"}" +
110116
"]," +
117+
"\"leader\":[" +
118+
"{" +
119+
"\"@type\":\"Person\"," +
120+
"\"sameAs\":[\"https://www.twitter.com/SportsUnlimited\",\"https://www.facebook.com/SportsUnlimited\"]" +
121+
"}" +
122+
"]," +
111123
"\"location\":{" +
112124
"\"@type\":\"Place\"," +
113125
"\"name\":\"Santa Clara City Library, Central Park Library\"," +
@@ -286,6 +298,16 @@ public void ToString_OfferEncodeDecode()
286298
Assert.Equal(encode, reencode);
287299
}
288300

301+
[Fact]
302+
public void ToString_Serialize_Null()
303+
{
304+
var encode = OpenActiveSerializer.Serialize((ScheduledSession)null);
305+
306+
output.WriteLine(encode);
307+
Assert.Equal("null", encode);
308+
}
309+
310+
289311

290312
private readonly SessionSeries nestedEvent = new OpenActive.NET.SessionSeries()
291313
{
@@ -318,5 +340,22 @@ public void SessionSeries_Nested_EncodeDecode()
318340
output.WriteLine(encode);
319341
Assert.Equal(nestedJson, encode);
320342
}
343+
344+
private readonly string organizationJson =
345+
"{\"@context\":\"https://openactive.io/\"," +
346+
"\"@type\":\"Organization\"," +
347+
"\"sameAs\":[\"https://www.twitter.com/SportsUnlimited\",\"https://www.facebook.com/SportsUnlimited\"]" +
348+
"}";
349+
350+
[Fact]
351+
public void ToString_EncodeDecode_SameAs()
352+
{
353+
var decode = OpenActiveSerializer.Deserialize<Organization>(organizationJson);
354+
var encode = OpenActiveSerializer.Serialize(decode);
355+
356+
output.WriteLine(organizationJson);
357+
output.WriteLine(encode);
358+
Assert.Equal(organizationJson, encode);
359+
}
321360
}
322361
}

OpenActive.NET.Test/OrderTest.cs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,9 @@ public OrderTest(ITestOutputHelper output)
110110
[Fact]
111111
public void OrderQuote_Deserialize_Accessors() {
112112
OrderQuote orderQuote = OpenActiveSerializer.Deserialize<OrderQuote>(json);
113-
Assert.Equal(new Uri("https://www.example.com/offer/1"), orderQuote.OrderedItem[0].AcceptedOffer.Id);
114-
Assert.Equal(new Uri("https://www.example.com/sessionseries/1"), orderQuote.OrderedItem[0].OrderedItem.Id);
115-
Assert.Equal(new Uri("https://www.example.com/seller/1"), orderQuote.Seller.Id);
113+
Assert.Equal(new Uri("https://www.example.com/offer/1"), orderQuote.OrderedItem[0].AcceptedOffer.Object.Id);
114+
Assert.Equal(new Uri("https://www.example.com/sessionseries/1"), orderQuote.OrderedItem[0].OrderedItem.Object.Id);
115+
Assert.Equal(new Uri("https://www.example.com/seller/1"), orderQuote.Seller.Object.Id);
116116
Assert.Equal(BrokerType.ResellerBroker, orderQuote.BrokerRole);
117117
Assert.Equal("Alan Peacock Way", orderQuote?.Broker?.Address?.StreetAddress);
118118
Assert.Equal("Geoff", orderQuote.Customer.GivenName);
@@ -125,7 +125,7 @@ public void OrderQuote_EncodeDecode()
125125
var encode = OpenActiveSerializer.Serialize(decode);
126126

127127
// Should cast this to ScheduledSession instead of Event
128-
Assert.IsType<ScheduledSession>(decode.OrderedItem[0].OrderedItem);
128+
Assert.IsType<ScheduledSession>(decode.OrderedItem[0].OrderedItem.Object);
129129

130130
output.WriteLine(json);
131131
output.WriteLine(encode);
@@ -136,6 +136,7 @@ public void OrderQuote_EncodeDecode()
136136
"\"@context\":\"https://openactive.io/\"," +
137137
"\"@type\":\"Order\"," +
138138
"\"@id\":\"https://example.com/api/orders/e11429ea-467f-4270-ab62-e47368996fe8\"," +
139+
"\"identifier\":\"e11429ea-467f-4270-ab62-e47368996fe8\"," +
139140
"\"bookingService\":{" +
140141
"\"@type\":\"BookingService\"," +
141142
"\"name\":\"Playwaze\"," +
@@ -320,18 +321,19 @@ public void Order_Deserialize_Accessors()
320321
{
321322
Order order = OpenActiveSerializer.Deserialize<Order>(complexJson);
322323
Assert.IsType<Order>(order);
323-
Assert.Equal(new Uri("https://example.com/events/452#/offers/878"), order.OrderedItem[0].AcceptedOffer.Id);
324-
Assert.IsType<ScheduledSession>(order.OrderedItem[0].OrderedItem);
325-
Assert.Equal("ScheduledSession", order.OrderedItem[0].OrderedItem.Type);
326-
Assert.Equal(new Uri("https://example.com/events/452/subEvents/132"), order.OrderedItem[0].OrderedItem.Id);
327-
Assert.Equal(new Uri("https://example.com/api/organisations/123"), order.Seller.Id);
328-
Assert.True(order.Seller.IsOrganization);
324+
Assert.Equal(new Guid("e11429ea-467f-4270-ab62-e47368996fe8"), order.Identifier);
325+
Assert.Equal(new Uri("https://example.com/events/452#/offers/878"), order.OrderedItem[0].AcceptedOffer.Object.Id);
326+
Assert.IsType<ScheduledSession>(order.OrderedItem[0].OrderedItem.Object);
327+
Assert.Equal("ScheduledSession", order.OrderedItem[0].OrderedItem.Object.Type);
328+
Assert.Equal(new Uri("https://example.com/events/452/subEvents/132"), order.OrderedItem[0].OrderedItem.Object.Id);
329+
Assert.Equal(new Uri("https://example.com/api/organisations/123"), order.Seller.Object.Id);
330+
Assert.True(order.Seller.Object.IsOrganization);
329331
Assert.Equal(BrokerType.AgentBroker, order.BrokerRole);
330332
Assert.Equal("Alan Peacock Way", order?.Broker?.Address?.StreetAddress);
331333
Assert.Equal("Geoff", order?.Customer.GivenName);
332334
Assert.Equal("EUCODE", order?.OrderedItem?[0]?.UnitTaxSpecification?[0]?.Identifier.GetClass<List<PropertyValue>>()?[0].Name);
333-
Assert.Equal(new TimeSpan(6,0,0,0), order?.OrderedItem?[0]?.AcceptedOffer?.ValidFromBeforeStartDate);
334-
Assert.Equal(new DateTimeOffset(2018, 10, 30, 11, 00, 00, 00, new TimeSpan()), ((ScheduledSession)order?.OrderedItem?[0]?.OrderedItem)?.StartDate);
335+
Assert.Equal(new TimeSpan(6,0,0,0), order?.OrderedItem?[0]?.AcceptedOffer.Object?.ValidFromBeforeStartDate);
336+
Assert.Equal(new DateTimeOffset(2018, 10, 30, 11, 00, 00, 00, new TimeSpan()), ((ScheduledSession)order?.OrderedItem?[0]?.OrderedItem.Object)?.StartDate);
335337
}
336338

337339
[Fact]
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
using Newtonsoft.Json;
2+
using OpenActive.NET;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using Xunit;
7+
using Xunit.Abstractions;
8+
namespace OpenActive.NET.Test
9+
{
10+
public class ReferenceValueTest
11+
{
12+
private readonly ITestOutputHelper output;
13+
14+
public ReferenceValueTest(ITestOutputHelper output)
15+
{
16+
this.output = output;
17+
}
18+
19+
private readonly string eventJson = "{\"@context\":\"https://openactive.io/\",\"@type\":\"ScheduledSession\",\"@id\":\"https://opensessions.io/api/session-series/1402CBP20150217#/subEvent/C5EE1E55-2DE6-44F7-A865-42F268A82C63\",\"identifier\":\"C5EE1E55-2DE6-44F7-A865-42F268A82C63\"}";
20+
21+
private readonly ScheduledSession @event = new OpenActive.NET.ScheduledSession()
22+
{
23+
Id = new Uri("https://opensessions.io/api/session-series/1402CBP20150217#/subEvent/C5EE1E55-2DE6-44F7-A865-42F268A82C63"),
24+
Identifier = "C5EE1E55-2DE6-44F7-A865-42F268A82C63"
25+
};
26+
27+
private readonly string referencedEventJson = "{\"@context\":\"https://openactive.io/\",\"@type\":\"ScheduledSession\",\"@id\":\"https://opensessions.io/api/session-series/1402CBP20150217#/subEvent/C5EE1E55-2DE6-44F7-A865-42F268A82C63\",\"identifier\":\"C5EE1E55-2DE6-44F7-A865-42F268A82C63\",\"superEvent\":\"https://opensessions.io/api/session-series/1402CBP20150217\"}";
28+
29+
private readonly ScheduledSession referencedEvent = new OpenActive.NET.ScheduledSession()
30+
{
31+
Id = new Uri("https://opensessions.io/api/session-series/1402CBP20150217#/subEvent/C5EE1E55-2DE6-44F7-A865-42F268A82C63"),
32+
Identifier = "C5EE1E55-2DE6-44F7-A865-42F268A82C63",
33+
SuperEvent = new Uri("https://opensessions.io/api/session-series/1402CBP20150217")
34+
};
35+
36+
private readonly string embeddedEventJson = "{\"@context\":\"https://openactive.io/\",\"@type\":\"ScheduledSession\",\"@id\":\"https://opensessions.io/api/session-series/1402CBP20150217#/subEvent/C5EE1E55-2DE6-44F7-A865-42F268A82C63\",\"identifier\":\"C5EE1E55-2DE6-44F7-A865-42F268A82C63\",\"superEvent\":{" +
37+
"\"@type\":\"SessionSeries\"," +
38+
"\"name\":\"Super!\"" +
39+
"}}";
40+
41+
private readonly ScheduledSession embeddedEvent = new OpenActive.NET.ScheduledSession()
42+
{
43+
Id = new Uri("https://opensessions.io/api/session-series/1402CBP20150217#/subEvent/C5EE1E55-2DE6-44F7-A865-42F268A82C63"),
44+
Identifier = "C5EE1E55-2DE6-44F7-A865-42F268A82C63",
45+
SuperEvent = new SessionSeries
46+
{
47+
Name = "Super!"
48+
}
49+
};
50+
51+
[Fact]
52+
public void ToString_EventWithNull_ReturnsExpectedJsonLd()
53+
{
54+
output.WriteLine(this.@event.ToString());
55+
Assert.Equal(this.eventJson, this.@event.ToString());
56+
}
57+
58+
[Fact]
59+
public void ToString_ReferencedEvent_ReturnsExpectedJsonLd()
60+
{
61+
output.WriteLine(this.referencedEvent.ToString());
62+
Assert.Equal(this.referencedEventJson, this.referencedEvent.ToString());
63+
}
64+
65+
[Fact]
66+
public void ToString_EmbeddedEvent_ReturnsExpectedJsonLd()
67+
{
68+
output.WriteLine(this.embeddedEvent.ToString());
69+
Assert.Equal(this.embeddedEventJson, this.embeddedEvent.ToString());
70+
}
71+
72+
[Fact]
73+
public void ScheduledSession_EventWithNull_Deserialize()
74+
{
75+
// Should recognise subclasses of Event when deserialising
76+
var decode = OpenActiveSerializer.Deserialize<ScheduledSession>(eventJson);
77+
output.WriteLine(eventJson);
78+
output.WriteLine("");
79+
output.WriteLine(decode.ToString());
80+
81+
// Test superEvent
82+
Assert.False(decode.SuperEvent.HasValue);
83+
Assert.Null(decode.SuperEvent.IdReference);
84+
Assert.Null(decode.SuperEvent.Object);
85+
}
86+
87+
[Fact]
88+
public void ScheduledSession_ReferencedEvent_Deserialize()
89+
{
90+
// Should recognise subclasses of Event when deserialising
91+
var decode = OpenActiveSerializer.Deserialize<ScheduledSession>(referencedEventJson);
92+
output.WriteLine(referencedEventJson);
93+
output.WriteLine("");
94+
output.WriteLine(decode.ToString());
95+
96+
// Test superEvent
97+
Assert.True(decode.SuperEvent.HasValue);
98+
Assert.Equal(new Uri("https://opensessions.io/api/session-series/1402CBP20150217"), decode.SuperEvent.IdReference);
99+
Assert.Null(decode.SuperEvent.Object);
100+
}
101+
102+
[Fact]
103+
public void ScheduledSession_EmbeddedEvent_Deserialize()
104+
{
105+
// Should recognise subclasses of Event when deserialising
106+
var decode = OpenActiveSerializer.Deserialize<ScheduledSession>(embeddedEventJson);
107+
output.WriteLine(embeddedEventJson);
108+
output.WriteLine("");
109+
output.WriteLine(decode.ToString());
110+
111+
// Test superEvent
112+
Assert.True(decode.SuperEvent.HasValue);
113+
Assert.NotNull(decode.SuperEvent.Object);
114+
Assert.Equal("Super!", decode.SuperEvent.Object.Name);
115+
}
116+
117+
[Fact]
118+
public void ScheduledSession_EventWithNull_EncodeDecode()
119+
{
120+
var decode = OpenActiveSerializer.Deserialize<ScheduledSession>(eventJson);
121+
var encode = OpenActiveSerializer.Serialize(decode);
122+
123+
output.WriteLine(eventJson);
124+
output.WriteLine(encode);
125+
Assert.Equal(eventJson, encode);
126+
}
127+
128+
[Fact]
129+
public void ScheduledSession_ReferencedEvent_EncodeDecode()
130+
{
131+
var decode = OpenActiveSerializer.Deserialize<ScheduledSession>(referencedEventJson);
132+
var encode = OpenActiveSerializer.Serialize(decode);
133+
134+
output.WriteLine(referencedEventJson);
135+
output.WriteLine(encode);
136+
Assert.Equal(referencedEventJson, encode);
137+
}
138+
139+
[Fact]
140+
public void ScheduledSession_EmbeddedEvent_EncodeDecode()
141+
{
142+
var decode = OpenActiveSerializer.Deserialize<ScheduledSession>(embeddedEventJson);
143+
var encode = OpenActiveSerializer.Serialize(decode);
144+
145+
output.WriteLine(embeddedEventJson);
146+
output.WriteLine(encode);
147+
Assert.Equal(embeddedEventJson, encode);
148+
}
149+
150+
[Fact]
151+
public void ReferenceValue_Object()
152+
{
153+
ReferenceValue<Event> sessionSeries = new SessionSeries();
154+
ReferenceValue<Event> @event = new Event();
155+
156+
Assert.NotNull(sessionSeries.Object);
157+
Assert.NotNull(@event.Object);
158+
}
159+
}
160+
}

OpenActive.NET.Test/SingleValuesTest.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ public void ScheduledSession_SuperEvent_Deserialize()
4848
Assert.Equal(15, decode.MaximumAttendeeCapacity);
4949

5050
// Test superEvent
51-
Assert.IsType<SessionSeries>(decode.SuperEvent.GetClass<SessionSeries>());
52-
Assert.Equal("Adult Supervised11-15yrs", decode.SuperEvent.GetClass<SessionSeries>().Name);
51+
Assert.IsType<SessionSeries>(decode.SuperEvent.Object);
52+
Assert.Equal("Adult Supervised11-15yrs", decode.SuperEvent.Object?.Name);
5353

5454
// Test superEvent.superEvent
55-
Assert.IsType<EventSeries>(decode.SuperEvent.GetClass<SessionSeries>().SuperEvent);
56-
Assert.Equal("11-15 Years Supervised Gym Sessions", decode.SuperEvent.GetClass<SessionSeries>().SuperEvent.Name);
55+
Assert.IsType<EventSeries>(decode.SuperEvent.Object?.SuperEvent);
56+
Assert.Equal("11-15 Years Supervised Gym Sessions", decode.SuperEvent.Object?.SuperEvent.Name);
5757
}
5858

5959
[Fact]

OpenActive.NET/ComparableSingleValue{T1,T2}.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace OpenActive.NET
1010
/// <typeparam name="T1">The first type the values can take.</typeparam>
1111
/// <typeparam name="T2">The second type the values can take.</typeparam>
1212
/// <seealso cref="IValue" />
13-
public readonly struct ComparableSingleValue<T1, T2> : IValue, IEquatable<ComparableSingleValue<T1, T2>>, IComparable<ComparableSingleValue<T1, T2>> where T1 : IComparable<T1> where T2 : IComparable<T2>
13+
public readonly struct ComparableSingleValue<T1, T2> : IValue, IValueAccessor, IEquatable<ComparableSingleValue<T1, T2>>, IComparable<ComparableSingleValue<T1, T2>> where T1 : IComparable<T1> where T2 : IComparable<T2>
1414
{
1515
private readonly T1 value1;
1616
private readonly T2 value2;

OpenActive.NET/IValue.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ public interface IValue
1111
/// Gets the non-null object representing the instance, useful for switch statements
1212
/// </summary>
1313
object Value { get; }
14+
}
1415

16+
/// <summary>
17+
/// Get a single value from one or more values.
18+
/// </summary>
19+
public interface IValueAccessor
20+
{
1521
/// <summary>
1622
/// Gets the nullable primative representing the instance, if it is of the type specified.
1723
/// </summary>

0 commit comments

Comments
 (0)