Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quantity.fromNumericalAmount, the inverse of getNumericalAmount #5052

Merged
merged 13 commits into from
Apr 28, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
* Fix #4998: removing the internal usage of the Serialization yaml mapper
* Fix #5005: status operations use the context `subresource` setting
* Fix #5022: adding additional buffering to ExecWatchInputStream
* Fix #5052: add Quantity.fromNumericalAmount, the inverse of getNumericalAmount
* Fix #5080: minimizing debug logs related to the backoff interval

#### Dependency Upgrade
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public void setFormat(String format) {
* If this is a memory Quantity, the result will represent bytes.<br>
* If this is a cpu Quantity, the result will represent cores.
*
* @return the formated amount as a number
* @return the formatted amount as a number
* @throws ArithmeticException
*/
@JsonIgnore
Expand Down Expand Up @@ -146,13 +146,39 @@ public static BigDecimal getAmountInBytes(Quantity quantity) throws ArithmeticEx

Quantity amountFormatPair = parse(value);
String formatStr = amountFormatPair.getFormat();

BigDecimal digit = new BigDecimal(amountFormatPair.getAmount());
BigDecimal multiple = getMultiple(formatStr);

return digit.multiply(multiple);
}

/**
* Constructs a new Quantity from the provided amountInBytes. This amount is converted
* to a value with the unit provided in desiredFormat.
*
* @param amountInBytes
* @param desiredFormat
* @see #getNumericalAmount()
* @return a new Quantity with the value of amountInBytes with units desiredFormat
*/
public static Quantity fromNumericalAmount(BigDecimal amountInBytes, String desiredFormat) {
if (desiredFormat == null || desiredFormat.isEmpty()) {
return new Quantity(amountInBytes.stripTrailingZeros().toPlainString());
}

BigDecimal scaledToDesiredFormat = amountInBytes.divide(getMultiple(desiredFormat), MathContext.DECIMAL64);

return new Quantity(scaledToDesiredFormat.stripTrailingZeros().toPlainString(), desiredFormat);
}

private static BigDecimal getMultiple(String formatStr) {
// Handle Decimal exponent case
if (containsAtLeastOneDigit(formatStr) && formatStr.length() > 1) {
int exponent = Integer.parseInt(formatStr.substring(1));
return new BigDecimal("10").pow(exponent, MathContext.DECIMAL64).multiply(new BigDecimal(amountFormatPair.getAmount()));
return new BigDecimal("10").pow(exponent, MathContext.DECIMAL64);
}

BigDecimal digit = new BigDecimal(amountFormatPair.getAmount());
BigDecimal multiple = new BigDecimal("1");
BigDecimal binaryFactor = new BigDecimal("2");
BigDecimal decimalFactor = new BigDecimal("10");
Expand Down Expand Up @@ -208,8 +234,7 @@ public static BigDecimal getAmountInBytes(Quantity quantity) throws ArithmeticEx
default:
throw new IllegalArgumentException("Invalid quantity format passed to parse");
}

return digit.multiply(multiple);
return multiple;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;

import java.math.BigDecimal;
import java.util.Collections;
Expand Down Expand Up @@ -199,4 +200,14 @@ void testIndexOfUnit(String input, int result) {
void indexOfUnit_whenBlankValueProvided_thenReturnsZero() {
assertThat(Quantity.indexOfUnit("")).isZero();
}

@ParameterizedTest
@ValueSource(strings = {
"129e6", "129e+6", "1234567890", "8Ki", "7Mi", "6Gi", "5Ti", "4Pi", "3Ei", "5n", "4u", "3m",
"9", "8k", "50k", "7M", "6G", "5T", "40T", "300T", "2P", "1E", ".5Mi", "0.5e-1", "1.1E-5" })
@DisplayName("Test fromAmountInBytes method")
void testFromAmountInBytes(String amount) {
Quantity quantity = new Quantity(amount);
assertThat(quantity).isEqualTo(Quantity.fromNumericalAmount(quantity.getNumericalAmount(), quantity.getFormat()));
}
}