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
69 changes: 69 additions & 0 deletions src/test/java/com/adyen/model/nexo/AbortRequestTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.adyen.model.nexo;

import static org.junit.jupiter.api.Assertions.assertEquals;

import com.adyen.terminal.serialization.TerminalAPIGsonBuilder;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.IOException;
import org.junit.jupiter.api.Test;

public class AbortRequestTest {

@Test
public void testShouldSerializeAndDeserializeFromMockFile() throws IOException {
String mockJson = NexoTestUtils.readResource("mocks/terminal-api/abort-request.json");
Gson terminalApiGson = TerminalAPIGsonBuilder.create();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Gson object is created within the test method. Since Gson instances are thread-safe and their creation can be expensive, it's a good practice to create it only once per class. Consider making terminalApiGson a private static final field in the AbortRequestTest class. This improves performance and code clarity.


AbortRequest deserializedAbortRequest = terminalApiGson.fromJson(mockJson, AbortRequest.class);
assertEquals("cancelled-by-shopper", deserializedAbortRequest.getAbortReason());
assertEquals(
MessageCategoryType.PAYMENT,
deserializedAbortRequest.getMessageReference().getMessageCategory());
assertEquals("service-id", deserializedAbortRequest.getMessageReference().getServiceID());
assertEquals("device-id", deserializedAbortRequest.getMessageReference().getDeviceID());
assertEquals("sale-id", deserializedAbortRequest.getMessageReference().getSaleID());
assertEquals("poi-id", deserializedAbortRequest.getMessageReference().getPOIID());
assertEquals(
"Abort requested",
deserializedAbortRequest
.getDisplayOutput()
.getOutputContent()
.getOutputText()
.get(0)
.getText());
assertEquals(
DeviceType.CUSTOMER_DISPLAY, deserializedAbortRequest.getDisplayOutput().getDevice());
assertEquals(
InfoQualifyType.ERROR, deserializedAbortRequest.getDisplayOutput().getInfoQualify());
assertEquals(
OutputFormatType.TEXT,
deserializedAbortRequest.getDisplayOutput().getOutputContent().getOutputFormat());

String serializedJson = terminalApiGson.toJson(deserializedAbortRequest);

JsonObject expectedJsonObject = JsonParser.parseString(mockJson).getAsJsonObject();
JsonObject serializedJsonObject = JsonParser.parseString(serializedJson).getAsJsonObject();
assertEquals(expectedJsonObject, serializedJsonObject);

AbortRequest roundTripAbortRequest =
terminalApiGson.fromJson(serializedJson, AbortRequest.class);
assertEquals(deserializedAbortRequest.getAbortReason(), roundTripAbortRequest.getAbortReason());
assertEquals(
deserializedAbortRequest.getMessageReference().getServiceID(),
roundTripAbortRequest.getMessageReference().getServiceID());
assertEquals(
deserializedAbortRequest.getMessageReference().getDeviceID(),
roundTripAbortRequest.getMessageReference().getDeviceID());
assertEquals(
deserializedAbortRequest.getMessageReference().getSaleID(),
roundTripAbortRequest.getMessageReference().getSaleID());
assertEquals(
deserializedAbortRequest.getMessageReference().getPOIID(),
roundTripAbortRequest.getMessageReference().getPOIID());
assertEquals(
deserializedAbortRequest.getDisplayOutput().getInfoQualify(),
roundTripAbortRequest.getDisplayOutput().getInfoQualify());
Comment on lines +52 to +67
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The round-trip validation is done by asserting a subset of the object's properties. This is brittle and incomplete. For example, MessageReference.MessageCategory is asserted during the initial deserialization but not in this round-trip check.

A more robust and maintainable approach would be to implement equals() and hashCode() methods on the AbortRequest class and its nested objects. This would allow you to replace these multiple assertions with a single, comprehensive check:

assertEquals(deserializedAbortRequest, roundTripAbortRequest);

This ensures that all fields are compared, making the test more thorough and easier to maintain when new fields are added to the model.

Suggested change
assertEquals(deserializedAbortRequest.getAbortReason(), roundTripAbortRequest.getAbortReason());
assertEquals(
deserializedAbortRequest.getMessageReference().getServiceID(),
roundTripAbortRequest.getMessageReference().getServiceID());
assertEquals(
deserializedAbortRequest.getMessageReference().getDeviceID(),
roundTripAbortRequest.getMessageReference().getDeviceID());
assertEquals(
deserializedAbortRequest.getMessageReference().getSaleID(),
roundTripAbortRequest.getMessageReference().getSaleID());
assertEquals(
deserializedAbortRequest.getMessageReference().getPOIID(),
roundTripAbortRequest.getMessageReference().getPOIID());
assertEquals(
deserializedAbortRequest.getDisplayOutput().getInfoQualify(),
roundTripAbortRequest.getDisplayOutput().getInfoQualify());
assertEquals(deserializedAbortRequest, roundTripAbortRequest);

}
}
59 changes: 59 additions & 0 deletions src/test/java/com/adyen/model/nexo/DisplayRequestTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.adyen.model.nexo;

import static org.junit.jupiter.api.Assertions.assertEquals;

import com.adyen.terminal.serialization.TerminalAPIGsonBuilder;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.IOException;
import org.junit.jupiter.api.Test;

public class DisplayRequestTest {

@Test
public void testShouldSerializeAndDeserializeFromMockFile() throws IOException {
String mockJson = NexoTestUtils.readResource("mocks/terminal-api/display-request.json");
Gson terminalApiGson = TerminalAPIGsonBuilder.create();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Gson object is created within the test method. Since Gson instances are thread-safe and their creation can be expensive, it's a good practice to create it only once per class. Consider making terminalApiGson a private static final field in the DisplayRequestTest class. This improves performance and code clarity.


DisplayRequest deserializedDisplayRequest =
terminalApiGson.fromJson(mockJson, DisplayRequest.class);
assertEquals(1, deserializedDisplayRequest.getDisplayOutput().size());
assertEquals(
DeviceType.CUSTOMER_DISPLAY,
deserializedDisplayRequest.getDisplayOutput().get(0).getDevice());
assertEquals(
InfoQualifyType.DISPLAY,
deserializedDisplayRequest.getDisplayOutput().get(0).getInfoQualify());
assertEquals(
OutputFormatType.TEXT,
deserializedDisplayRequest.getDisplayOutput().get(0).getOutputContent().getOutputFormat());
assertEquals(
"Please present card",
deserializedDisplayRequest
.getDisplayOutput()
.get(0)
.getOutputContent()
.getOutputText()
.get(0)
.getText());

String serializedJson = terminalApiGson.toJson(deserializedDisplayRequest);

JsonObject expectedJsonObject = JsonParser.parseString(mockJson).getAsJsonObject();
JsonObject serializedJsonObject = JsonParser.parseString(serializedJson).getAsJsonObject();
assertEquals(expectedJsonObject, serializedJsonObject);

DisplayRequest roundTripDisplayRequest =
terminalApiGson.fromJson(serializedJson, DisplayRequest.class);
assertEquals(
"Please present card",
roundTripDisplayRequest
.getDisplayOutput()
.get(0)
.getOutputContent()
.getOutputText()
.get(0)
.getText());
Comment on lines +49 to +57
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This round-trip validation only checks a single, deeply nested property. This is very incomplete and provides little value. The initial deserialization checks more properties (e.g., Device, InfoQualify).

A more robust and maintainable approach would be to implement equals() and hashCode() methods on the DisplayRequest class and its nested objects. This would allow you to replace this assertion with a single, comprehensive check:

assertEquals(deserializedDisplayRequest, roundTripDisplayRequest);

This ensures that all fields are compared, making the test more thorough and easier to maintain.

    assertEquals(deserializedDisplayRequest, roundTripDisplayRequest);

}
}
68 changes: 68 additions & 0 deletions src/test/java/com/adyen/model/nexo/LoginRequestTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.adyen.model.nexo;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import com.adyen.terminal.serialization.TerminalAPIGsonBuilder;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.IOException;
import org.junit.jupiter.api.Test;

public class LoginRequestTest {

@Test
public void testShouldSerializeAndDeserializeFromMockFile() throws IOException {
String mockJson = NexoTestUtils.readResource("mocks/terminal-api/login-request.json");
Gson terminalApiGson = TerminalAPIGsonBuilder.create();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Gson object is created within the test method. Since Gson instances are thread-safe and their creation can be expensive, it's a good practice to create it only once per class. Consider making terminalApiGson a private static final field in the LoginRequestTest class. This improves performance and code clarity.


LoginRequest deserializedLoginRequest = terminalApiGson.fromJson(mockJson, LoginRequest.class);
assertEquals("2026-03-26T10:15:30Z", deserializedLoginRequest.getDateTime().toString());
assertEquals("adyen", deserializedLoginRequest.getSaleSoftware().getManufacturerID());
assertEquals("register-app", deserializedLoginRequest.getSaleSoftware().getApplicationName());
assertEquals("1.0.0", deserializedLoginRequest.getSaleSoftware().getSoftwareVersion());
assertEquals("cert-123", deserializedLoginRequest.getSaleSoftware().getCertificationCode());
assertEquals(2, deserializedLoginRequest.getSaleTerminalData().getSaleCapabilities().size());
assertEquals(
SaleCapabilitiesType.CASHIER_DISPLAY,
deserializedLoginRequest.getSaleTerminalData().getSaleCapabilities().get(0));
assertEquals(
SaleCapabilitiesType.CUSTOMER_DISPLAY,
deserializedLoginRequest.getSaleTerminalData().getSaleCapabilities().get(1));
assertEquals(
TerminalEnvironmentType.ATTENDED,
deserializedLoginRequest.getSaleTerminalData().getTerminalEnvironment());
assertEquals("group-1", deserializedLoginRequest.getSaleTerminalData().getTotalsGroupID());
assertTrue(deserializedLoginRequest.isTrainingModeFlag());
assertEquals("en", deserializedLoginRequest.getOperatorLanguage());
assertEquals("operator-1", deserializedLoginRequest.getOperatorID());
assertEquals("shift-1", deserializedLoginRequest.getShiftNumber());
assertEquals(TokenRequestedType.TRANSACTION, deserializedLoginRequest.getTokenRequestedType());
assertEquals(2, deserializedLoginRequest.getCustomerOrderReq().size());
assertEquals(CustomerOrderReqType.OPEN, deserializedLoginRequest.getCustomerOrderReq().get(0));
assertEquals(
CustomerOrderReqType.CLOSED, deserializedLoginRequest.getCustomerOrderReq().get(1));
assertEquals("poi-serial-1", deserializedLoginRequest.getPOISerialNumber());

String serializedJson = terminalApiGson.toJson(deserializedLoginRequest);

JsonObject expectedJsonObject = JsonParser.parseString(mockJson).getAsJsonObject();
JsonObject serializedJsonObject = JsonParser.parseString(serializedJson).getAsJsonObject();
assertEquals(expectedJsonObject, serializedJsonObject);

LoginRequest roundTripLoginRequest =
terminalApiGson.fromJson(serializedJson, LoginRequest.class);
assertEquals(
deserializedLoginRequest.getDateTime().toString(),
roundTripLoginRequest.getDateTime().toString());
assertEquals(
deserializedLoginRequest.getTokenRequestedType(),
roundTripLoginRequest.getTokenRequestedType());
assertEquals(
deserializedLoginRequest.getCustomerOrderReq(),
roundTripLoginRequest.getCustomerOrderReq());
assertEquals(
deserializedLoginRequest.getPOISerialNumber(), roundTripLoginRequest.getPOISerialNumber());
Comment on lines +56 to +66
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The round-trip validation is done by asserting a subset of the object's properties. This is brittle and incomplete. Many properties asserted during the initial deserialization (e.g., SaleSoftware details, SaleTerminalData) are not checked here.

A more robust and maintainable approach would be to implement equals() and hashCode() methods on the LoginRequest class and its nested objects. This would allow you to replace these multiple assertions with a single, comprehensive check:

assertEquals(deserializedLoginRequest, roundTripLoginRequest);

This ensures that all fields are compared, making the test more thorough and easier to maintain.

    assertEquals(deserializedLoginRequest, roundTripLoginRequest);

}
}
49 changes: 49 additions & 0 deletions src/test/java/com/adyen/model/nexo/MessageHeaderTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.adyen.model.nexo;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;

import com.adyen.terminal.serialization.TerminalAPIGsonBuilder;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Test;

public class MessageHeaderTest {

@Test
public void testShouldSerializeAndDeserializeFromMockFile() throws IOException {
String mockJson = NexoTestUtils.readResource("mocks/terminal-api/message-header.json");
Gson terminalApiGson = TerminalAPIGsonBuilder.create();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Gson object is created within the test method. Since Gson instances are thread-safe and their creation can be expensive, it's a good practice to create it only once per class. Consider making terminalApiGson a private static final field in the MessageHeaderTest class. This improves performance and code clarity.


MessageHeader deserializedMessageHeader =
terminalApiGson.fromJson(mockJson, MessageHeader.class);
String serializedJson = terminalApiGson.toJson(deserializedMessageHeader);

JsonObject expectedJsonObject = JsonParser.parseString(mockJson).getAsJsonObject();
JsonObject serializedJsonObject = JsonParser.parseString(serializedJson).getAsJsonObject();
assertEquals(expectedJsonObject, serializedJsonObject);

MessageHeader roundTripMessageHeader =
terminalApiGson.fromJson(serializedJson, MessageHeader.class);
assertEquals(
deserializedMessageHeader.getProtocolVersion(),
roundTripMessageHeader.getProtocolVersion());
assertEquals(
deserializedMessageHeader.getMessageClass(), roundTripMessageHeader.getMessageClass());
assertEquals(
deserializedMessageHeader.getMessageCategory(),
roundTripMessageHeader.getMessageCategory());
assertEquals(
deserializedMessageHeader.getMessageType(), roundTripMessageHeader.getMessageType());
assertEquals(deserializedMessageHeader.getServiceID(), roundTripMessageHeader.getServiceID());
assertEquals(deserializedMessageHeader.getDeviceID(), roundTripMessageHeader.getDeviceID());
assertEquals(deserializedMessageHeader.getSaleID(), roundTripMessageHeader.getSaleID());
assertEquals(deserializedMessageHeader.getPOIID(), roundTripMessageHeader.getPOIID());
Comment on lines +34 to +47
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While these assertions cover all properties of MessageHeader, the test can be made more concise and maintainable.

By implementing equals() and hashCode() on the MessageHeader class, you can replace all these individual assertions with a single line:

assertEquals(deserializedMessageHeader, roundTripMessageHeader);

This approach is cleaner and scales better if new fields are added to MessageHeader in the future.

    assertEquals(deserializedMessageHeader, roundTripMessageHeader);

}
}
45 changes: 45 additions & 0 deletions src/test/java/com/adyen/model/nexo/MessageReferenceTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.adyen.model.nexo;

import static org.junit.jupiter.api.Assertions.assertEquals;

import com.adyen.terminal.serialization.TerminalAPIGsonBuilder;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.IOException;
import org.junit.jupiter.api.Test;

public class MessageReferenceTest {

@Test
public void testShouldSerializeAndDeserializeFromMockFile() throws IOException {
String mockJson = NexoTestUtils.readResource("mocks/terminal-api/message-reference.json");
Gson terminalApiGson = TerminalAPIGsonBuilder.create();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Gson object is created within the test method. Since Gson instances are thread-safe and their creation can be expensive, it's a good practice to create it only once per class. Consider making terminalApiGson a private static final field in the MessageReferenceTest class. This improves performance and code clarity.


MessageReference deserializedMessageReference =
terminalApiGson.fromJson(mockJson, MessageReference.class);
assertEquals(MessageCategoryType.PAYMENT, deserializedMessageReference.getMessageCategory());
assertEquals("service-id", deserializedMessageReference.getServiceID());
assertEquals("device-id", deserializedMessageReference.getDeviceID());
assertEquals("sale-id", deserializedMessageReference.getSaleID());
assertEquals("poi-id", deserializedMessageReference.getPOIID());

String serializedJson = terminalApiGson.toJson(deserializedMessageReference);

JsonObject expectedJsonObject = JsonParser.parseString(mockJson).getAsJsonObject();
JsonObject serializedJsonObject = JsonParser.parseString(serializedJson).getAsJsonObject();
assertEquals(expectedJsonObject, serializedJsonObject);

MessageReference roundTripMessageReference =
terminalApiGson.fromJson(serializedJson, MessageReference.class);
assertEquals(
deserializedMessageReference.getMessageCategory(),
roundTripMessageReference.getMessageCategory());
assertEquals(
deserializedMessageReference.getServiceID(), roundTripMessageReference.getServiceID());
assertEquals(
deserializedMessageReference.getDeviceID(), roundTripMessageReference.getDeviceID());
assertEquals(deserializedMessageReference.getSaleID(), roundTripMessageReference.getSaleID());
assertEquals(deserializedMessageReference.getPOIID(), roundTripMessageReference.getPOIID());
Comment on lines +35 to +43
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While these assertions cover all properties of MessageReference, the test can be made more concise and maintainable.

By implementing equals() and hashCode() on the MessageReference class, you can replace all these individual assertions with a single line:

assertEquals(deserializedMessageReference, roundTripMessageReference);

This approach is cleaner and scales better if new fields are added to MessageReference in the future.

    assertEquals(deserializedMessageReference, roundTripMessageReference);

}
}
20 changes: 20 additions & 0 deletions src/test/java/com/adyen/model/nexo/NexoTestUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.adyen.model.nexo;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

final class NexoTestUtils {

private NexoTestUtils() {}

static String readResource(String fileName) throws IOException {
ClassLoader classLoader = NexoTestUtils.class.getClassLoader();
try (InputStream fileStream = classLoader.getResourceAsStream(fileName)) {
if (fileStream == null) {
throw new IOException("Unable to load resource: " + fileName);
}
return new String(fileStream.readAllBytes(), StandardCharsets.UTF_8);
}
}
}
24 changes: 24 additions & 0 deletions src/test/resources/mocks/terminal-api/abort-request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"MessageReference": {
"MessageCategory": "Payment",
"ServiceID": "service-id",
"DeviceID": "device-id",
"SaleID": "sale-id",
"POIID": "poi-id"
},
"AbortReason": "cancelled-by-shopper",
"DisplayOutput": {
"OutputContent": {
"OutputText": [
{
"Text": "Abort requested"
}
],
"OutputFormat": "Text"
},
"ResponseRequiredFlag": false,
"MinimumDisplayTime": 3,
"Device": "CustomerDisplay",
"InfoQualify": "Error"
}
}
18 changes: 18 additions & 0 deletions src/test/resources/mocks/terminal-api/display-request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"DisplayOutput": [
{
"OutputContent": {
"OutputText": [
{
"Text": "Please present card"
}
],
"OutputFormat": "Text"
},
"ResponseRequiredFlag": true,
"MinimumDisplayTime": 5,
"Device": "CustomerDisplay",
"InfoQualify": "Display"
}
]
}
27 changes: 27 additions & 0 deletions src/test/resources/mocks/terminal-api/login-request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"DateTime": "2026-03-26T10:15:30Z",
"SaleSoftware": {
"ManufacturerID": "adyen",
"ApplicationName": "register-app",
"SoftwareVersion": "1.0.0",
"CertificationCode": "cert-123"
},
"SaleTerminalData": {
"SaleCapabilities": [
"CashierDisplay",
"CustomerDisplay"
],
"TerminalEnvironment": "Attended",
"TotalsGroupID": "group-1"
},
"TrainingModeFlag": true,
"OperatorLanguage": "en",
"OperatorID": "operator-1",
"ShiftNumber": "shift-1",
"TokenRequestedType": "Transaction",
"CustomerOrderReq": [
"Open",
"Closed"
],
"POISerialNumber": "poi-serial-1"
}
10 changes: 10 additions & 0 deletions src/test/resources/mocks/terminal-api/message-header.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"ProtocolVersion": "3.0",
"MessageClass": "Service",
"MessageCategory": "Payment",
"MessageType": "Request",
"ServiceID": "service-id",
"DeviceID": "device-id",
"SaleID": "sale-id",
"POIID": "poi-id"
}
Loading
Loading