> request) {
+
+ final GetVoidedStatementRequest.Builder, ?> builder = GetVoidedStatementRequest.builder();
+
+ request.accept(builder);
+
+ return getVoidedStatement(builder.build());
+
+ }
+
+ /**
+ * Gets a StatementResult object, a list of Statements. If additional results are available, an
+ * URL to retrieve them will be included in the StatementResult Object.
+ *
+ *
+ * The returned ResponseEntity contains the response headers and StatementResult.
+ *
+ *
+ * @return the ResponseEntity
+ */
+ public Mono> getStatements() {
+
+ return getStatements(GetStatementsRequest.builder().build());
+ }
+
+ /**
+ * Gets a StatementResult object, a list of Statements. If additional results are available, an
+ * URL to retrieve them will be included in the StatementResult Object.
+ *
+ *
+ * The returned ResponseEntity contains the response headers and StatementResult.
+ *
+ *
+ * @param request The parameters of the get statements request
+ *
+ * @return the ResponseEntity
+ */
+ public Mono> getStatements(GetStatementsRequest request) {
+
+ Map queryParams = new HashMap<>();
+
+ return this.webClient
+
+ .method(request.getMethod())
+
+ .uri(u -> request.url(u, queryParams).build(queryParams))
+
+ .retrieve()
+
+ .toEntity(StatementResult.class);
+
+ }
+
+ /**
+ * Gets a StatementResult object, a list of Statements. If additional results are available, an
+ * URL to retrieve them will be included in the StatementResult Object.
+ *
+ *
+ * The returned ResponseEntity contains the response headers and StatementResult.
+ *
+ *
+ * @param request The Consumer Builder for the get statements request
+ *
+ * @return the ResponseEntity
+ */
+ public Mono> getStatements(
+ Consumer request) {
+
+ final GetStatementsRequest.Builder builder = GetStatementsRequest.builder();
+
+ request.accept(builder);
+
+ return getStatements(builder.build());
+
+ }
+
+ /**
+ * Gets a StatementResult object, a list of Statements. If additional results are available, an
+ * URL to retrieve them will be included in the StatementResult Object.
+ *
+ *
+ * The returned ResponseEntity contains the response headers and StatementResult.
+ *
+ *
+ * @param request The parameters of the get more statements request
+ *
+ * @return the ResponseEntity
+ */
+ public Mono> getMoreStatements(GetMoreStatementsRequest request) {
+
+ Map queryParams = new HashMap<>();
+
+ return this.webClient
+
+ .method(request.getMethod())
+
+ .uri(u -> request.url(u, queryParams).build(queryParams))
+
+ .retrieve()
+
+ .toEntity(StatementResult.class);
+
+ }
+
+ /**
+ * Gets a StatementResult object, a list of Statements. If additional results are available, an
+ * URL to retrieve them will be included in the StatementResult Object.
+ *
+ *
+ * The returned ResponseEntity contains the response headers and StatementResult.
+ *
+ *
+ * @param request The Consumer Builder for the get more statements request
+ *
+ * @return the ResponseEntity
+ */
+ public Mono> getMoreStatements(
+ Consumer request) {
+
+ final GetMoreStatementsRequest.Builder builder = GetMoreStatementsRequest.builder();
+
+ request.accept(builder);
+
+ return getMoreStatements(builder.build());
+
+ }
+
/**
* Gets a single document specified by the given stateId activity, agent, and optional
* registration.
diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/GetMoreStatementsRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/GetMoreStatementsRequestTests.java
new file mode 100644
index 00000000..39cdb842
--- /dev/null
+++ b/xapi-client/src/test/java/dev/learning/xapi/client/GetMoreStatementsRequestTests.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved.
+ */
+package dev.learning.xapi.client;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import java.net.URI;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+/**
+ * GetMoreStatementsRequest Tests.
+ *
+ * @author Thomas Turrell-Croft
+ */
+@DisplayName("GetMoreStatementsRequest Tests")
+class GetMoreStatementsRequestTests {
+
+ @Test
+ void whenBuildingGetMoreStatementsRequestWithAllParametersThenNoExceptionIsThrown() {
+
+ // When Building GetMoreStatementsRequest With All Parameters
+ GetMoreStatementsRequest.Builder builder = GetMoreStatementsRequest.builder()
+
+ .more(
+ URI.create("https://example.com/xapi/statements/869cc589-76fa-4283-8e96-eea86f9124e1"));
+
+ // Then No Exception Is Thrown
+ assertDoesNotThrow(() -> builder.build());
+
+ }
+
+ @Test
+ void whenBuildingGetMoreStatementsRequestWithoutMoreThenNullPointerExceptionIsThrown() {
+
+ // When Building GetMoreStatementsRequest Without More
+ GetMoreStatementsRequest.Builder builder = GetMoreStatementsRequest.builder();
+
+ // Then NullPointerException Is Thrown
+ assertThrows(NullPointerException.class, () -> builder.build());
+
+ }
+
+
+}
diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/GetStatementsRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/GetStatementsRequestTests.java
new file mode 100644
index 00000000..5e4355cd
--- /dev/null
+++ b/xapi-client/src/test/java/dev/learning/xapi/client/GetStatementsRequestTests.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved.
+ */
+package dev.learning.xapi.client;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import dev.learning.xapi.model.StatementFormat;
+import java.net.URI;
+import java.time.Instant;
+import java.util.UUID;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+/**
+ * GetStatementsRequest Tests.
+ *
+ * @author Thomas Turrell-Croft
+ */
+@DisplayName("GetStatementsRequest Tests")
+class GetStatementsRequestTests {
+
+ @Test
+ void whenBuildingGetStatementsRequestWithAllParametersThenNoExceptionIsThrown() {
+
+ // When Building GetStatementsRequest With All Parameters
+ GetStatementsRequest.Builder builder = GetStatementsRequest.builder()
+
+ .agent(a -> a.name("A N Other").mbox("mailto:another@example.com"))
+
+ .verb(URI.create("http://adlnet.gov/expapi/verbs/answered"))
+
+ .activity(URI.create("https://example.com/activity/1"))
+
+ .registration(UUID.fromString("dbf5d9e8-d2aa-4d57-9754-b11e3f195fe3"))
+
+ .relatedActivities(true)
+
+ .relatedAgents(true)
+
+ .since(Instant.parse("2016-01-01T00:00:00Z"))
+
+ .until(Instant.parse("2018-01-01T00:00:00Z"))
+
+ .limit(10)
+
+ .format(StatementFormat.CANONICAL)
+
+ .attachments(true)
+
+ .ascending(true);
+
+ // Then No Exception Is Thrown
+ assertDoesNotThrow(() -> builder.build());
+
+ }
+
+}
diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java
index 1debc04d..f3bbd585 100644
--- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java
+++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java
@@ -1,11 +1,17 @@
/*
- * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved.
+ * Copyright 2016rue-2023 Berry Cloud Ltd. All rights reserved.
*/
package dev.learning.xapi.client;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import dev.learning.xapi.model.Statement;
+import dev.learning.xapi.model.StatementFormat;
+import dev.learning.xapi.model.Verb;
+import java.time.Instant;
+import java.util.Locale;
+import java.util.UUID;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
@@ -39,9 +45,8 @@ void setUp() throws Exception {
mockWebServer = new MockWebServer();
mockWebServer.start();
- String baseUrl = String.format("http://localhost:%s", mockWebServer.getPort());
+ webClientBuilder.baseUrl(mockWebServer.url("").toString());
- webClientBuilder.baseUrl(baseUrl);
client = new XapiClient(webClientBuilder);
}
@@ -51,6 +56,484 @@ void tearDown() throws Exception {
mockWebServer.shutdown();
}
+ // Get Statement
+
+ @Test
+ void whenGettingStatementThenMethodIsGet() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ // When Getting Statements
+ client.getStatement(r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6")).block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Method Is Get
+ assertThat(recordedRequest.getMethod(), is("GET"));
+ }
+
+ @Test
+ void whenGettingStatementThenPathIsExpected() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ // When Getting Statement
+ client.getStatement(r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6")).block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Path Is Expected
+ assertThat(recordedRequest.getPath(),
+ is("/statements?statementId=4df42866-40e7-45b6-bf7c-8d5fccbdccd6"));
+ }
+
+ @Test
+ void whenGettingStatementThenBodyIsInstanceOfStatement() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")
+
+ .setBody(
+ "{\"actor\":{\"objectType\":\"Agent\",\"name\":\"A N Other\",\"mbox\":\"mailto:another@example.com\"},\"verb\":{\"id\":\"http://adlnet.gov/expapi/verbs/attempted\",\"display\":{\"und\":\"attempted\"}},\"object\":{\"objectType\":\"Activity\",\"id\":\"https://example.com/activity/simplestatement\",\"definition\":{\"name\":{\"en\":\"Simple Statement\"}}}}")
+ .addHeader("Content-Type", "application/json; charset=utf-8"));
+
+ // When Getting Statement
+ var response = client.getStatement(r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6")).block();
+
+ // Then Body Is Instance Of Statement
+ assertThat(response.getBody(), instanceOf(Statement.class));
+ }
+
+ @Test
+ void whenGettingStatementWithAttachmentsThenPathIsExpected() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ // When Getting Statement With Attachments
+ client.getStatement(r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6").attachments(true))
+ .block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Path Is Expected
+ assertThat(recordedRequest.getPath(),
+ is("/statements?statementId=4df42866-40e7-45b6-bf7c-8d5fccbdccd6&attachments=true"));
+ }
+
+ @Test
+ void whenGettingStatementWithCanonicalFormatThenPathIsExpected() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ // When Getting Statement With Canonical Format
+ client
+ .getStatement(
+ r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6").format(StatementFormat.CANONICAL))
+ .block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Path Is Expected
+ assertThat(recordedRequest.getPath(),
+ is("/statements?statementId=4df42866-40e7-45b6-bf7c-8d5fccbdccd6&format=canonical"));
+ }
+
+ // Posting Statements
+
+ @Test
+ void whenPostingStatementsThenMethodIsPost() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ final Statement attemptedStatement = Statement.builder()
+
+ .actor(a -> a.name("A N Other").mbox("mailto:another@example.com"))
+
+ .verb(Verb.ATTEMPTED)
+
+ .activityObject(o -> o.id("https://example.com/activity/simplestatement")
+ .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement")))
+
+ .build();
+
+ final Statement passedStatement = attemptedStatement.toBuilder().verb(Verb.PASSED).build();
+
+ Statement statements[] = {attemptedStatement, passedStatement};
+
+ // When posting Statements
+ client.postStatements(r -> r.statements(statements)).block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Method Is Post
+ assertThat(recordedRequest.getMethod(), is("POST"));
+ }
+
+ @Test
+ void whenPostingStatementsThenBodyIsExpected() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ final Statement attemptedStatement = Statement.builder()
+
+ .actor(a -> a.name("A N Other").mbox("mailto:another@example.com"))
+
+ .verb(Verb.ATTEMPTED)
+
+ .activityObject(o -> o.id("https://example.com/activity/simplestatement")
+ .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement")))
+
+ .build();
+
+ final Statement passedStatement = attemptedStatement.toBuilder().verb(Verb.PASSED).build();
+
+ Statement statements[] = {attemptedStatement, passedStatement};
+
+ // When Posting Statements
+ client.postStatements(r -> r.statements(statements)).block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Body Is Expected
+ assertThat(recordedRequest.getBody().readUtf8(), is(
+ "[{\"actor\":{\"name\":\"A N Other\",\"mbox\":\"mailto:another@example.com\"},\"verb\":{\"id\":\"http://adlnet.gov/expapi/verbs/attempted\",\"display\":{\"und\":\"attempted\"}},\"object\":{\"objectType\":\"Activity\",\"id\":\"https://example.com/activity/simplestatement\",\"definition\":{\"name\":{\"en\":\"Simple Statement\"}}}},{\"actor\":{\"name\":\"A N Other\",\"mbox\":\"mailto:another@example.com\"},\"verb\":{\"id\":\"http://adlnet.gov/expapi/verbs/passed\",\"display\":{\"und\":\"passed\"}},\"object\":{\"objectType\":\"Activity\",\"id\":\"https://example.com/activity/simplestatement\",\"definition\":{\"name\":{\"en\":\"Simple Statement\"}}}}]"));
+ }
+
+ @Test
+ void whenPostingStatementsThenContentTypeHeaderIsApplicationJson() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ final Statement attemptedStatement = Statement.builder()
+
+ .actor(a -> a.name("A N Other").mbox("mailto:another@example.com"))
+
+ .verb(Verb.ATTEMPTED)
+
+ .activityObject(o -> o.id("https://example.com/activity/simplestatement")
+ .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement")))
+
+ .build();
+
+ final Statement passedStatement = attemptedStatement.toBuilder().verb(Verb.PASSED).build();
+
+ Statement statements[] = {attemptedStatement, passedStatement};
+
+ // When Posting Statements
+ client.postStatements(r -> r.statements(statements)).block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Content Type Header Is Application Json
+ assertThat(recordedRequest.getHeader("content-type"), is("application/json"));
+ }
+
+ // Posting a Statement
+
+ @Test
+ void whenPostingStatementThenMethodIsPost() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")
+ .setBody("[\"19a74a3f-7354-4254-aa4a-1c39ab4f2ca7\"]")
+ .setHeader("Content-Type", "application/json"));
+
+ // When posting Statement
+ client.postStatement(
+ r -> r.statement(s -> s.actor(a -> a.name("A N Other").mbox("mailto:another@example.com"))
+
+ .verb(Verb.ATTEMPTED)
+
+ .activityObject(o -> o.id("https://example.com/activity/simplestatement")
+ .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement")))))
+ .block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Method Is Post
+ assertThat(recordedRequest.getMethod(), is("POST"));
+ }
+
+ @Test
+ void whenPostingStatementThenBodyIsExpected() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")
+ .setBody("[\"19a74a3f-7354-4254-aa4a-1c39ab4f2ca7\"]")
+ .setHeader("Content-Type", "application/json"));
+
+ // When Posting Statement
+ client.postStatement(
+ r -> r.statement(s -> s.actor(a -> a.name("A N Other").mbox("mailto:another@example.com"))
+
+ .verb(Verb.ATTEMPTED)
+
+ .activityObject(o -> o.id("https://example.com/activity/simplestatement")
+ .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement")))))
+ .block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Body Is Expected
+ assertThat(recordedRequest.getBody().readUtf8(), is(
+ "{\"actor\":{\"name\":\"A N Other\",\"mbox\":\"mailto:another@example.com\"},\"verb\":{\"id\":\"http://adlnet.gov/expapi/verbs/attempted\",\"display\":{\"und\":\"attempted\"}},\"object\":{\"objectType\":\"Activity\",\"id\":\"https://example.com/activity/simplestatement\",\"definition\":{\"name\":{\"en\":\"Simple Statement\"}}}}"));
+ }
+
+ @Test
+ void whenPostingStatementThenContentTypeHeaderIsApplicationJson() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")
+ .setBody("[\"19a74a3f-7354-4254-aa4a-1c39ab4f2ca7\"]")
+ .setHeader("Content-Type", "application/json"));
+
+ // When Posting Statement
+ client.postStatement(
+ r -> r.statement(s -> s.actor(a -> a.name("A N Other").mbox("mailto:another@example.com"))
+
+ .verb(Verb.ATTEMPTED)
+
+ .activityObject(o -> o.id("https://example.com/activity/simplestatement")
+ .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement")))))
+ .block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Content Type Header Is Application Json
+ assertThat(recordedRequest.getHeader("content-type"), is("application/json"));
+ }
+
+ // Get Voided Statement
+
+ @Test
+ void whenGettingVoidedStatementThenMethodIsGet() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ // When Getting Voided Statement
+ client.getVoidedStatement(r -> r.id(UUID.fromString("4df42866-40e7-45b6-bf7c-8d5fccbdccd6")))
+ .block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Method Is Get
+ assertThat(recordedRequest.getMethod(), is("GET"));
+ }
+
+ @Test
+ void whenGettingVoidedStatementThenPathIsExpected() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ // When Getting Voided Statement
+ client.getVoidedStatement(r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6")).block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Path Is Expected
+ assertThat(recordedRequest.getPath(),
+ is("/statements?voidedStatementId=4df42866-40e7-45b6-bf7c-8d5fccbdccd6"));
+ }
+
+ @Test
+ void whenGettingVoidedStatementWithAttachmentsThenPathIsExpected() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ // When Getting Voided Statement With Attachments
+ client.getStatement(r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6").attachments(true))
+ .block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Path Is Expected
+ assertThat(recordedRequest.getPath(),
+ is("/statements?statementId=4df42866-40e7-45b6-bf7c-8d5fccbdccd6&attachments=true"));
+ }
+
+ @Test
+ void whenGettingVoidedStatementWithCanonicalFormatThenPathIsExpected()
+ throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ // When Getting Voided Statement With Canonical Format
+ client
+ .getStatement(
+ r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6").format(StatementFormat.CANONICAL))
+ .block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Path Is Expected
+ assertThat(recordedRequest.getPath(),
+ is("/statements?statementId=4df42866-40e7-45b6-bf7c-8d5fccbdccd6&format=canonical"));
+ }
+
+ // Get Statements
+
+ @Test
+ void whenGettingStatementsThenMethodIsGet() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ // When Getting Statements
+ client.getStatements().block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Method Is Get
+ assertThat(recordedRequest.getMethod(), is("GET"));
+ }
+
+
+ @Test
+ void whenGettingStatementsThenPathIsExpected() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ // When Getting Statements
+ client.getStatements().block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Path Is Expected
+ assertThat(recordedRequest.getPath(), is("/statements"));
+ }
+
+ @Test
+ void whenGettingStatementsWithAllParametersThenPathIsExpected() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ // When Getting Statements With All Parameters
+ client.getStatements(r -> r
+
+ .agent(a -> a.name("A N Other").mbox("mailto:another@example.com"))
+
+ .verb("http://adlnet.gov/expapi/verbs/answered")
+
+ .activity("https://example.com/activity/1")
+
+ .registration("dbf5d9e8-d2aa-4d57-9754-b11e3f195fe3")
+
+ .relatedActivities(true)
+
+ .relatedAgents(true)
+
+ .since(Instant.parse("2016-01-01T00:00:00Z"))
+
+ .until(Instant.parse("2018-01-01T00:00:00Z"))
+
+ .limit(10)
+
+ .format(StatementFormat.CANONICAL)
+
+ .attachments(true)
+
+ .ascending(true)
+
+ ).block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Path Is Expected
+ assertThat(recordedRequest.getPath(), is(
+ "/statements?agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22mailto%3Aanother%40example.com%22%7D&verb=http%3A%2F%2Fadlnet.gov%2Fexpapi%2Fverbs%2Fanswered&activity=https%3A%2F%2Fexample.com%2Factivity%2F1&since=2016-01-01T00%3A00%3A00Z&until=2018-01-01T00%3A00%3A00Z®istration=dbf5d9e8-d2aa-4d57-9754-b11e3f195fe3&related_activities=true&related_agents=true&limit=10&format=canonical&attachments=true&ascending=true"));
+ }
+
+ @Test
+ void whenGettingStatementsWithAgentParameterThenPathIsExpected() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ // When Getting Statements With Agent Parameter
+ client.getStatements(r -> r
+
+ .agent(a -> a.name("A N Other").mbox("mailto:another@example.com"))
+
+ ).block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Path Is Expected
+ assertThat(recordedRequest.getPath(), is(
+ "/statements?agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22mailto%3Aanother%40example.com%22%7D"));
+ }
+
+ @Test
+ void whenGettingStatementsWithVerbParameterThenPathIsExpected() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ // When Getting Statements With Verb Parameter
+ client.getStatements(r -> r
+
+ .verb("http://adlnet.gov/expapi/verbs/answered")
+
+ ).block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Path Is Expected
+ assertThat(recordedRequest.getPath(),
+ is("/statements?verb=http%3A%2F%2Fadlnet.gov%2Fexpapi%2Fverbs%2Fanswered"));
+ }
+
+ @Test
+ void whenGettingStatementsWithActivityParameterThenPathIsExpected() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ // When Getting Statements With Activity Parameter
+ client.getStatements(r -> r
+
+ .activity("https://example.com/activity/1")
+
+ ).block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Path Is Expected
+ assertThat(recordedRequest.getPath(),
+ is("/statements?activity=https%3A%2F%2Fexample.com%2Factivity%2F1"));
+ }
+
+
+
+ @Test
+ void whenGettingMoreStatementsThenRequestMethodIsGet() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ // When Getting Statements With Activity Parameter
+ client.getMoreStatements(r -> r
+
+ .more(mockWebServer.url("/xapi/statements/869cc589-76fa-4283-8e96-eea86f9124e1").uri())
+
+ ).block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Method Is Get
+ assertThat(recordedRequest.getMethod(), is("GET"));
+ }
+
+ @Test
+ void whenGettingMoreStatementsThenRequestURLExpected() throws InterruptedException {
+
+ mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content"));
+
+ // When Getting Statements With Activity Parameter
+ client.getMoreStatements(r -> r
+
+ .more(mockWebServer.url("/xapi/statements/869cc589-76fa-4283-8e96-eea86f9124e1").uri())
+
+ ).block();
+
+ RecordedRequest recordedRequest = mockWebServer.takeRequest();
+
+ // Then Request URL Is Expected
+ assertThat(recordedRequest.getRequestUrl(),
+ is(mockWebServer.url("/xapi/statements/869cc589-76fa-4283-8e96-eea86f9124e1")));
+ }
+
// Get Single State
@Test
@@ -73,8 +556,6 @@ void whenGettingASingleStateThenMethodIsGet() throws InterruptedException {
assertThat(recordedRequest.getMethod(), is("GET"));
}
-
-
@Test
void whenGettingASingleStateThenPathIsExpected() throws InterruptedException {
diff --git a/xapi-model/src/main/java/dev/learning/xapi/model/StatementFormat.java b/xapi-model/src/main/java/dev/learning/xapi/model/StatementFormat.java
new file mode 100644
index 00000000..558cd21c
--- /dev/null
+++ b/xapi-model/src/main/java/dev/learning/xapi/model/StatementFormat.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved.
+ */
+
+package dev.learning.xapi.model;
+
+/**
+ * This enumeration class represents all valid Statement formats.
+ *
+ * @author Thomas Turrell-Croft
+ */
+public enum StatementFormat {
+
+ IDS("ids"),
+
+ EXACT("exact"),
+
+ CANONICAL("canonical");
+
+ private final String format;
+
+ StatementFormat(String format) {
+ this.format = format;
+ }
+
+ public String getFormat() {
+ return format;
+ }
+
+ @Override
+ public String toString() {
+ return format;
+ }
+
+ // **Warning** do not add fields that are not required by the xAPI specification.
+}
diff --git a/xapi-model/src/test/java/dev/learning/xapi/model/StatementFormatTests.java b/xapi-model/src/test/java/dev/learning/xapi/model/StatementFormatTests.java
new file mode 100644
index 00000000..fb4613da
--- /dev/null
+++ b/xapi-model/src/test/java/dev/learning/xapi/model/StatementFormatTests.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved.
+ */
+
+package dev.learning.xapi.model;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import org.junit.jupiter.api.Test;
+
+class StatementFormatTests {
+
+ @Test
+ void whenCallingToStringOnCanonicalEnumResultIsLowerCase() {
+
+ // When Calling ToString On Canonical Enum
+ String result = StatementFormat.CANONICAL.toString();
+
+ // Result Is Lower Case
+ assertThat(result, is("canonical"));
+ }
+
+ @Test
+ void whenCallingGetFormatOnCanonicalEnumResultIsLowerCase() {
+
+ // When Calling GetFormat On Canonical Enum
+ String result = StatementFormat.CANONICAL.getFormat();
+
+ // Result Is Lower Case
+ assertThat(result, is("canonical"));
+ }
+
+ @Test
+ void whenCallingToStringOnExactEnumResultIsLowerCase() {
+
+ // When Calling ToString On Exact Enum
+ String result = StatementFormat.EXACT.toString();
+
+ // Result Is Lower Case
+ assertThat(result, is("exact"));
+ }
+
+ @Test
+ void whenCallingGetFormatOnExactEnumResultIsLowerCase() {
+
+ // When Calling GetFormat On Exact Enum
+ String result = StatementFormat.EXACT.getFormat();
+
+ // Result Is Lower Case
+ assertThat(result, is("exact"));
+ }
+
+ @Test
+ void whenCallingToStringOnIdsEnumResultIsLowerCase() {
+
+ // When Calling ToString On Ids Enum
+ String result = StatementFormat.IDS.toString();
+
+ // Result Is Lower Case
+ assertThat(result, is("ids"));
+ }
+
+ @Test
+ void whenCallingGetFormatOnIdsEnumResultIsLowerCase() {
+
+ // When Calling GetFormat On Ids Enum
+ String result = StatementFormat.IDS.getFormat();
+
+ // Result Is Lower Case
+ assertThat(result, is("ids"));
+ }
+
+}