| 1 | /* | |
| 2 | * Copyright 2004 the original author or authors. | |
| 3 | * | |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
| 5 | * you may not use this file except in compliance with the License. | |
| 6 | * You may obtain a copy of the License at | |
| 7 | * | |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
| 9 | * | |
| 10 | * Unless required by applicable law or agreed to in writing, software | |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 13 | * See the License for the specific language governing permissions and | |
| 14 | * limitations under the License. | |
| 15 | */ | |
| 16 | package com.ancientprogramming.fixedformat4j.format.impl; | |
| 17 | ||
| 18 | import com.ancientprogramming.fixedformat4j.format.FormatInstructions; | |
| 19 | import org.apache.commons.lang3.StringUtils; | |
| 20 | import org.slf4j.Logger; | |
| 21 | import org.slf4j.LoggerFactory; | |
| 22 | ||
| 23 | import java.math.BigDecimal; | |
| 24 | import java.math.RoundingMode; | |
| 25 | import java.text.DecimalFormat; | |
| 26 | ||
| 27 | /** | |
| 28 | * Base class for formatting decimal data | |
| 29 | * | |
| 30 | * @author Jacob von Eyben - <a href="https://eybenconsult.com">https://eybenconsult.com</a> | |
| 31 | * @since 1.0.0 | |
| 32 | */ | |
| 33 | public abstract class AbstractDecimalFormatter<T extends Number> extends AbstractNumberFormatter<T> { | |
| 34 | ||
| 35 | private static final Logger LOG = LoggerFactory.getLogger(AbstractDecimalFormatter.class); | |
| 36 | ||
| 37 | /** {@inheritDoc} */ | |
| 38 | public String asString(T obj, FormatInstructions instructions) { | |
| 39 | BigDecimal roundedValue = null; | |
| 40 | int decimals = instructions.getFixedFormatDecimalData().getDecimals(); | |
| 41 |
1
1. asString : negated conditional → KILLED |
if (obj != null) { |
| 42 |
1
1. asString : negated conditional → KILLED |
BigDecimal value = obj instanceof BigDecimal ? (BigDecimal)obj : BigDecimal.valueOf(obj.doubleValue()); |
| 43 | ||
| 44 | RoundingMode roundingMode = instructions.getFixedFormatDecimalData().getRoundingMode(); | |
| 45 | ||
| 46 | roundedValue = value.setScale(decimals, roundingMode); | |
| 47 | ||
| 48 | if (LOG.isDebugEnabled()) { | |
| 49 | LOG.debug("Value before rounding = '{}', value after rounding = '{}', decimals = {}, rounding mode = {}", value, roundedValue, decimals, roundingMode); | |
| 50 | } | |
| 51 | } | |
| 52 | | |
| 53 | DecimalFormat formatter = new DecimalFormat(); | |
| 54 |
1
1. asString : removed call to java/text/DecimalFormat::setDecimalSeparatorAlwaysShown → KILLED |
formatter.setDecimalSeparatorAlwaysShown(true); |
| 55 |
1
1. asString : removed call to java/text/DecimalFormat::setMaximumFractionDigits → KILLED |
formatter.setMaximumFractionDigits(decimals); |
| 56 | ||
| 57 | char decimalSeparator = formatter.getDecimalFormatSymbols().getDecimalSeparator(); | |
| 58 | char groupingSeparator = formatter.getDecimalFormatSymbols().getGroupingSeparator(); | |
| 59 | String zeroString = String.format("0%c0", decimalSeparator); | |
| 60 | ||
| 61 |
1
1. asString : negated conditional → KILLED |
String rawString = roundedValue != null ? formatter.format(roundedValue) : zeroString; |
| 62 | if (LOG.isDebugEnabled()) { | |
| 63 | LOG.debug("rawString: {} - G[{}] D[{}]", rawString, groupingSeparator, decimalSeparator); | |
| 64 | } | |
| 65 | rawString = rawString.replaceAll("\\" + groupingSeparator, ""); | |
| 66 | boolean useDecimalDelimiter = instructions.getFixedFormatDecimalData().isUseDecimalDelimiter(); | |
| 67 | ||
| 68 | String beforeDelimiter = rawString.substring(0, rawString.indexOf(decimalSeparator)); | |
| 69 |
1
1. asString : Replaced integer addition with subtraction → KILLED |
String afterDelimiter = rawString.substring(rawString.indexOf(decimalSeparator)+1, rawString.length()); |
| 70 | if (LOG.isDebugEnabled()) { | |
| 71 | LOG.debug("beforeDelimiter[{}], afterDelimiter[{}]", beforeDelimiter, afterDelimiter); | |
| 72 | } | |
| 73 | ||
| 74 | //trim decimals | |
| 75 | afterDelimiter = StringUtils.substring(afterDelimiter, 0, decimals); | |
| 76 | afterDelimiter = StringUtils.rightPad(afterDelimiter, decimals, '0'); | |
| 77 | ||
| 78 |
1
1. asString : negated conditional → KILLED |
String delimiter = useDecimalDelimiter ? String.valueOf(instructions.getFixedFormatDecimalData().getDecimalDelimiter()) : ""; |
| 79 | String result = beforeDelimiter + delimiter + afterDelimiter; | |
| 80 | if (LOG.isDebugEnabled()) { | |
| 81 | LOG.debug("result[{}]", result); | |
| 82 | } | |
| 83 |
1
1. asString : replaced return value with "" for com/ancientprogramming/fixedformat4j/format/impl/AbstractDecimalFormatter::asString → KILLED |
return result; |
| 84 | } | |
| 85 | | |
| 86 | protected String getStringToConvert(String string, FormatInstructions instructions) { | |
| 87 | String toConvert = string; | |
| 88 | boolean useDecimalDelimiter = instructions.getFixedFormatDecimalData().isUseDecimalDelimiter(); | |
| 89 |
1
1. getStringToConvert : negated conditional → KILLED |
if (useDecimalDelimiter) { |
| 90 | char delimiter = instructions.getFixedFormatDecimalData().getDecimalDelimiter(); | |
| 91 | toConvert = toConvert.replace(String.valueOf(delimiter), ""); // | |
| 92 | } | |
| 93 | boolean applyNegativeSign = false; | |
| 94 | final Character negativeSignChar = instructions.getFixedFormatNumberData().getNegativeSign(); | |
| 95 |
2
1. getStringToConvert : negated conditional → KILLED 2. getStringToConvert : negated conditional → KILLED |
if (negativeSignChar != null && toConvert.startsWith(negativeSignChar.toString())) { |
| 96 | toConvert = toConvert.replaceFirst(negativeSignChar.toString(), ""); | |
| 97 | applyNegativeSign = true; | |
| 98 | } | |
| 99 | ||
| 100 | int decimals = instructions.getFixedFormatDecimalData().getDecimals(); | |
| 101 | final boolean theZeroString = toConvert.matches("^[0]+$"); | |
| 102 | //only change the string to convert if data contains decimals AND is not the zero string | |
| 103 |
3
1. getStringToConvert : changed conditional boundary → SURVIVED 2. getStringToConvert : negated conditional → KILLED 3. getStringToConvert : negated conditional → KILLED |
if (decimals > 0 && !theZeroString) { |
| 104 | //ensuring the string to convert is at least as long as the decimals length | |
| 105 | toConvert = StringUtils.leftPad(toConvert, decimals, "0"); | |
| 106 |
1
1. getStringToConvert : Replaced integer subtraction with addition → KILLED |
String beforeDelimiter = toConvert.substring(0, toConvert.length()-decimals); |
| 107 |
1
1. getStringToConvert : Replaced integer subtraction with addition → KILLED |
String afterDelimiter = toConvert.substring(toConvert.length()-decimals); |
| 108 | toConvert = beforeDelimiter + '.' + afterDelimiter; | |
| 109 | } | |
| 110 |
1
1. getStringToConvert : negated conditional → KILLED |
if (applyNegativeSign) { |
| 111 | toConvert = "-".concat(toConvert); | |
| 112 | } | |
| 113 |
1
1. getStringToConvert : replaced return value with "" for com/ancientprogramming/fixedformat4j/format/impl/AbstractDecimalFormatter::getStringToConvert → KILLED |
return toConvert; |
| 114 | } | |
| 115 | } | |
Mutations | ||
| 41 |
1.1 |
|
| 42 |
1.1 |
|
| 54 |
1.1 |
|
| 55 |
1.1 |
|
| 61 |
1.1 |
|
| 69 |
1.1 |
|
| 78 |
1.1 |
|
| 83 |
1.1 |
|
| 89 |
1.1 |
|
| 95 |
1.1 2.2 |
|
| 103 |
1.1 2.2 3.3 |
|
| 106 |
1.1 |
|
| 107 |
1.1 |
|
| 110 |
1.1 |
|
| 113 |
1.1 |