Skip to content

Commit

Permalink
CORE-18180 Correct StateRef.toString (#1327)
Browse files Browse the repository at this point in the history
The index in `StateRef.toString` was being formatted which added commas
to the output. This created an invalid string representation of a
`StateRef`, causing errors if we ever called `StateRef.parse` on the
output of `StateRef.toString`.

Rely on normal string concatenation instead of `MessageFormat.format` to
resolve this.
  • Loading branch information
lankydan authored Nov 7, 2023
1 parent 6e43f24 commit 3901a3c
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.text.MessageFormat;
import java.util.Objects;

/**
Expand Down Expand Up @@ -72,7 +71,8 @@ public static StateRef parse(@NotNull final String value, DigestService digestSe
final int lastIndexOfDelimiter = value.lastIndexOf(DELIMITER);
if (lastIndexOfDelimiter == -1) {
throw new IllegalArgumentException(
MessageFormat.format("Failed to parse a StateRef from the specified value. At least one delimiter ({0}) is expected in value: {1}.", DELIMITER, value)
"Failed to parse a StateRef from the specified value. At least one delimiter (" + DELIMITER + ") " +
"is expected in value: " + value + "."
);
}

Expand All @@ -84,12 +84,12 @@ public static StateRef parse(@NotNull final String value, DigestService digestSe
return new StateRef(transactionId, index);
} catch (NumberFormatException numberFormatException) {
throw new IllegalArgumentException(
MessageFormat.format("Failed to parse a StateRef from the specified value. The index is malformed: {0}.", value),
"Failed to parse a StateRef from the specified value. The index is malformed: " + value + ".",
numberFormatException
);
} catch (IllegalArgumentException illegalArgumentException) {
throw new IllegalArgumentException(
MessageFormat.format("Failed to parse a StateRef from the specified value. The transaction ID is malformed: {0}.", value),
"Failed to parse a StateRef from the specified value. The transaction ID is malformed: " + value + ".",
illegalArgumentException
);
}
Expand Down Expand Up @@ -126,6 +126,6 @@ public int hashCode() {
*/
@Override
public String toString() {
return MessageFormat.format("{0}{1}{2}", transactionId, DELIMITER, index);
return transactionId + DELIMITER + index;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

import net.corda.v5.application.crypto.DigestService;
import net.corda.v5.crypto.SecureHash;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
Expand All @@ -26,21 +31,21 @@ void parseValidValue() {

final StateRef stateRef = new StateRef(secureHash, Integer.parseUnsignedInt(value.substring(lastIndexOfDelimiter + 1)));

Assertions.assertEquals(StateRef.parse(value, digestService).getTransactionId().toString(), stateRef.getTransactionId().toString());
assertEquals(StateRef.parse(value, digestService).getTransactionId().toString(), stateRef.getTransactionId().toString());
}

@Test
void parseMalformedWithZeroDelimiter() {
final String value = "XXX";
final String errorMessage = assertThrows(IllegalArgumentException.class, () -> StateRef.parse(value, digestService)).getMessage();
Assertions.assertEquals(String.format("Failed to parse a StateRef from the specified value. At least one delimiter (%s) is expected in value: %s.", DELIMITER, value), errorMessage);
assertEquals(String.format("Failed to parse a StateRef from the specified value. At least one delimiter (%s) is expected in value: %s.", DELIMITER, value), errorMessage);
}

@Test
void parseMalformedIndex() {
final String value = ":asdf:a";
final String errorMessage = assertThrows(IllegalArgumentException.class, () -> StateRef.parse(value, digestService)).getMessage();
Assertions.assertEquals(String.format("Failed to parse a StateRef from the specified value. The index is malformed: %s.", value), errorMessage);
assertEquals(String.format("Failed to parse a StateRef from the specified value. The index is malformed: %s.", value), errorMessage);
}

@Test
Expand All @@ -57,6 +62,31 @@ void parseMalformedTransactionId() {

final String errorMessage = assertThrows(IllegalArgumentException.class, () -> StateRef.parse(value, digestService)).getMessage();

Assertions.assertEquals(String.format("Failed to parse a StateRef from the specified value. The transaction ID is malformed: %s.", value), errorMessage);
assertEquals(String.format("Failed to parse a StateRef from the specified value. The transaction ID is malformed: %s.", value), errorMessage);
}

@ParameterizedTest(name = "Parse large state ref index and reparse into state ref {0}")
@MethodSource("stateRefIndexes")
void parseLargeValueAndReparse(int index) {
final String value = "SHA-256D:ED87C7285E1E34BF5E46302086F76317ACE9B17AEF7BD086EE09A5ACBD17CEA4:" + index;
final int lastIndexOfDelimiter = value.lastIndexOf(DELIMITER);
final String subStringBeforeDelimiter = value.substring(0, lastIndexOfDelimiter);
final SecureHash secureHash = mock(SecureHash.class);

doReturn(secureHash).when(digestService).parseSecureHash(subStringBeforeDelimiter);
doReturn(subStringBeforeDelimiter).when(secureHash).toString();

final StateRef stateRef = StateRef.parse(value, digestService);

assertEquals(stateRef, StateRef.parse(stateRef.toString(), digestService));
}

public static Stream<Arguments> stateRefIndexes() {
return Stream.of(
Arguments.of(1000),
Arguments.of(1001),
Arguments.of(99999999),
Arguments.of(Integer.MAX_VALUE)
);
}
}

0 comments on commit 3901a3c

Please sign in to comment.