Commit 46bb90c5 authored by 35V LG84's avatar 35V LG84

Prepare for BigDecimal changes with Scala 2.13

New type `TacklerReal` with explicit `MathContext`
constructor argument.
Signed-off-by: 35V LG84's avatar35V LG84 <35vlg84-x4e6b92@e257.fi>
parent 127184fd
Pipeline #68204012 passed with stage
in 8 minutes and 30 seconds
......@@ -20,6 +20,8 @@ New features and changes in this release:
* Equity export
** Create equity transactions in sorting order of commodities
** Record commodity on equity txn's subject line
* Prepare for BigDecimal changes in Scala 2.13
** New type `TacklerReal` with explicit `MathContext` constructor argument
** ...
......
......@@ -16,6 +16,7 @@
*/
package fi.e257.tackler.core
import fi.e257.tackler.math.{TacklerReal, ZERO}
import fi.e257.tackler.model._
import scala.collection.mutable
......@@ -37,11 +38,11 @@ object Accumulator {
def registerStream[T](txns: Txns, accounts: Filtering[AccumulatorPosting])(reporter: (RegisterEntry => Seq[T])): Seq[T] = {
val registerEngine = new mutable.HashMap[String, BigDecimal]()
val registerEngine = new mutable.HashMap[String, TacklerReal]()
txns.flatMap(txn => {
val registerPostings = txn.posts.map({ p =>
val newTotal = registerEngine.getOrElse(p.atnKey, BigDecimal(0)) + p.amount
val newTotal = registerEngine.getOrElse(p.atnKey, ZERO) + p.amount
registerEngine.update(p.atnKey, newTotal)
AccumulatorPosting(p, newTotal)
......
......@@ -18,12 +18,14 @@ package fi.e257.tackler.core
import cats.implicits._
import fi.e257.tackler.api.Metadata
import fi.e257.tackler.math._
import fi.e257.tackler.model._
class Balance(val title: String,
class Balance(
val title: String,
val bal: Seq[BalanceTreeNode],
val deltas: Map[Option[Commodity], BigDecimal],
val deltas: Map[Option[Commodity], TacklerReal],
val metadata: Option[Metadata]) {
def isEmpty: Boolean = bal.isEmpty
......@@ -39,9 +41,9 @@ object Balance {
* @return list of balance tree nodes
*/
@SuppressWarnings(Array("org.wartremover.warts.Recursion"))
protected def getBalanceTreeNodes(
me: (AccountTreeNode, BigDecimal),
accSums: Seq[(AccountTreeNode, BigDecimal)])
protected def getBalanceTreeNodes(
me: (AccountTreeNode, TacklerReal),
accSums: Seq[(AccountTreeNode, TacklerReal)])
: Seq[BalanceTreeNode] = {
val (myAccTN, mySum) = me
......@@ -59,7 +61,7 @@ object Balance {
val myChildsSum = childsBalanceTrees
.filter(btn => btn.acctn.parent === myAccTN.account)
.map(btn => btn.subAccTreeSum)
.sum
.realSum
val myBTN = BalanceTreeNode(myAccTN, myChildsSum + mySum, mySum)
......@@ -78,9 +80,9 @@ object Balance {
"org.wartremover.warts.Recursion",
"org.wartremover.warts.TraversableOps"))
protected def bubbleUpAccTN(
myAccTNSum: (AccountTreeNode, BigDecimal),
accSums: Seq[(AccountTreeNode, BigDecimal)])
: Seq[(AccountTreeNode, BigDecimal)] = {
myAccTNSum: (AccountTreeNode, TacklerReal),
accSums: Seq[(AccountTreeNode, TacklerReal)])
: Seq[(AccountTreeNode, TacklerReal)] = {
val myAccTN = myAccTNSum._1
......@@ -103,7 +105,7 @@ object Balance {
val name = myAccTN.parent.split(":").last
val newParent = AccountTreeNode(myAccTN.depth - 1, myAccTN.root, par, account, name, myAccTN.commodity)
bubbleUpAccTN((newParent, BigDecimal(0)), accSums) ++ List(myAccTNSum)
bubbleUpAccTN((newParent, ZERO), accSums) ++ List(myAccTNSum)
} else {
// I am depth 2 and I don't have parent, => let's create root account
// end of recursion
......@@ -113,7 +115,7 @@ object Balance {
val name = myAccTN.parent
val newParent = AccountTreeNode(myAccTN.depth - 1, myAccTN.root, par, account, name, myAccTN.commodity)
List((newParent, BigDecimal(0)), myAccTNSum)
List((newParent, ZERO), myAccTNSum)
}
} else {
// my parent exists, just bubble up together
......@@ -129,12 +131,12 @@ object Balance {
// resulting size of this set is "small"
// e.g. max size is size of Chart of Accounts
// TODO: AccountTreeNode: provide default groupBy machinery
val accountSums: Seq[(AccountTreeNode, BigDecimal)] = txns
val accountSums: Seq[(AccountTreeNode, TacklerReal)] = txns
.flatMap(txn => txn.posts)
.groupBy(p => AccountTreeNode.groupBy(p.acctn))
.map((kv: (String, Seq[Posting])) => {
val post = kv._2.head
val accSum = kv._2.map(_.amount).sum
val accSum = kv._2.map(_.amount).realSum
(post.acctn, accSum)
}).toSeq
......@@ -150,7 +152,7 @@ object Balance {
}).distinct
// Get all root accounts
val roots: Seq[(AccountTreeNode, BigDecimal)] =
val roots: Seq[(AccountTreeNode, TacklerReal)] =
completeCoASumTree.filter({case (acctn, _) => acctn.depth === 1})
// Start from root's and get all subtree BalanceTreeNodes
......@@ -167,20 +169,20 @@ object Balance {
val fbal = bal.filter(accounts.predicate)
if (fbal.nonEmpty) {
val deltas: Map[Option[Commodity], BigDecimal] = fbal
val deltas: Map[Option[Commodity], TacklerReal] = fbal
.groupBy(_.acctn.commStr)
.map({ case (c, bs) =>
if (c === "") {
(None, bs.map(_.accountSum).sum)
(None, bs.map(_.accountSum).realSum)
} else {
(Some(new Commodity(c)), bs.map(_.accountSum).sum)
(Some(new Commodity(c)), bs.map(_.accountSum).realSum)
}
})
new Balance(title, fbal, deltas, txnData.getMetadata(accounts))
} else {
new Balance(title, Seq.empty[BalanceTreeNode],
Map.empty[Option[Commodity], BigDecimal], txnData.getMetadata(accounts))
Map.empty[Option[Commodity], TacklerReal], txnData.getMetadata(accounts))
}
}
}
/*
* Copyright 2019 E257.FI
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package fi.e257.tackler.math
import java.math.MathContext
object TacklerReal {
private def mathContext: MathContext = MathContext.UNLIMITED
@SuppressWarnings(Array("org.wartremover.warts.Overloading"))
def apply(i: Int): BigDecimal = BigDecimal(i, mathContext)
@SuppressWarnings(Array("org.wartremover.warts.Overloading"))
def apply(l: Long): BigDecimal = BigDecimal(l, mathContext)
@SuppressWarnings(Array("org.wartremover.warts.Overloading"))
def apply(d: Double): BigDecimal = BigDecimal(d, mathContext)
@SuppressWarnings(Array("org.wartremover.warts.Overloading"))
def apply(x: String): BigDecimal = BigDecimal(x, mathContext)
}
/*
* Copyright 2019 E257.FI
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package fi.e257.tackler
/**
* Scala 2.13.0 changes BigDecimal behaviour in breaking way
* compared to 2.12 and 2.11
*
* See:
* - https://github.com/scala/bug/issues/11592
* - https://github.com/scala/bug/issues/11590
*/
package object math {
type TacklerReal = scala.math.BigDecimal
val ZERO = TacklerReal(0)
implicit class TacklerSequenceOps(val seq: Seq[TacklerReal]) {
/**
* Calculate sum using correct MathContext
*
* This could be removed when StdLib sum is fixed:
* https://github.com/scala/bug/issues/11592
*
* @return sum of items in sequence
*/
def realSum: TacklerReal = seq.fold(TacklerReal(0))(_ + _)
}
implicit class TacklerBigDecimalOps(val r: BigDecimal) {
/**
* Check if value is zero, does NOT use epsilon
*
* @return true if value is zero
*/
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def isZero: Boolean = r == ZERO
}
}
/*
* Copyright 2016-2018 E257.FI
* Copyright 2016-2019 E257.FI
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -16,6 +16,8 @@
*/
package fi.e257.tackler.model
import fi.e257.tackler.math.TacklerReal
object OrderByAccumulatorPosting extends Ordering[AccumulatorPosting] {
def compare(before: AccumulatorPosting, after: AccumulatorPosting): Int = {
before.post.acctn.account.compareTo(after.post.acctn.account)
......@@ -24,9 +26,9 @@ object OrderByAccumulatorPosting extends Ordering[AccumulatorPosting] {
final case class AccumulatorPosting(
post: Posting,
runningTotal: BigDecimal
runningTotal: TacklerReal
) {
def account: String = post.acctn.account
def amount: BigDecimal = post.amount
def amount: TacklerReal = post.amount
def commodity: Option[Commodity] = post.acctn.commodity
}
/*
* Copyright 2016-2018 E257.FI
* Copyright 2016-2019 E257.FI
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -16,10 +16,12 @@
*/
package fi.e257.tackler.model
import fi.e257.tackler.math.TacklerReal
final case class BalanceTreeNode(
acctn: AccountTreeNode,
subAccTreeSum: BigDecimal,
accountSum: BigDecimal
subAccTreeSum: TacklerReal,
accountSum: TacklerReal
)
object OrderByPost extends Ordering[BalanceTreeNode] {
......
......@@ -15,9 +15,10 @@
*
*/
package fi.e257.tackler.model
import cats.implicits._
import cats.implicits._
import fi.e257.tackler.core.TxnException
import fi.e257.tackler.math._
/**
* Note about commodity support:
......@@ -36,14 +37,14 @@ import fi.e257.tackler.core.TxnException
*/
final case class Posting(
acctn: AccountTreeNode,
amount: BigDecimal,
amount: TacklerReal,
// todo: fix / rename these (position?, exchange? amount, commodity)
txnAmount: BigDecimal,
txnAmount: TacklerReal,
isTotalAmount: Boolean,
txnCommodity: Option[Commodity],
comment: Option[String]) {
if (amount.compareTo(BigDecimal(0)) === 0) {
if (amount.isZero) {
throw new TxnException("Zero sum postings are not allowed (is it typo?): " + acctn.account)
}
......@@ -72,7 +73,7 @@ final case class Posting(
object Posting {
def txnSum(posts: Posts): BigDecimal = {
posts.foldLeft(BigDecimal(0))(_ + _.txnAmount)
def txnSum(posts: Posts): TacklerReal = {
posts.map(_.txnAmount).realSum
}
}
......@@ -15,11 +15,12 @@
*
*/
package fi.e257.tackler.model
import java.time.ZonedDateTime
import cats.implicits._
import fi.e257.tackler.api.{TxnHeader, TxnTS}
import fi.e257.tackler.core.TxnException
import fi.e257.tackler.math._
object OrderByTxn extends Ordering[Transaction] {
def compare(before: Transaction, after: Transaction): Int = {
......@@ -31,7 +32,7 @@ final case class Transaction(
header: TxnHeader,
posts: Posts) {
if (BigDecimal(0).compareTo(Posting.txnSum(posts)) =!= 0) {
if (!Posting.txnSum(posts).isZero) {
throw new TxnException("TXN postings do not zero: " + Posting.txnSum(posts).toString())
}
......
......@@ -20,16 +20,16 @@ import java.time.{LocalDate, LocalDateTime, ZonedDateTime}
import java.util.UUID
import cats.implicits._
import scala.collection.JavaConverters
import fi.e257.tackler.api.{GeoPoint, TxnHeader}
import fi.e257.tackler.core.{AccountException, CfgKeys, CommodityException, Settings, TacklerException, TxnException}
import fi.e257.tackler.model.{AccountTreeNode, Commodity, Posting, Posts, Transaction, Txns}
import fi.e257.tackler.core._
import fi.e257.tackler.math.TacklerReal
import fi.e257.tackler.model._
import fi.e257.tackler.parser.TxnParser._
import org.slf4j.{Logger, LoggerFactory}
import scala.util.{Failure, Success}
import scala.collection.JavaConverters
import scala.util.control.NonFatal
import scala.util.{Failure, Success}
/**
* Handler utilities for ANTLR Parser Contexts.
......@@ -110,13 +110,13 @@ abstract class CtxHandler {
}
}
protected def handleAmount(amountCtx: AmountContext): BigDecimal = {
BigDecimal(amountCtx.getText())
protected def handleAmount(amountCtx: AmountContext): TacklerReal = {
TacklerReal(amountCtx.getText())
}
protected def handleValuePosition(postingCtx: PostingContext): (
BigDecimal,
BigDecimal,
TacklerReal,
TacklerReal,
Boolean,
Option[Commodity],
Option[Commodity]) = {
......@@ -260,9 +260,9 @@ abstract class CtxHandler {
})
val geo = Option(metaCtx.txn_meta_location()).map(geoCtx => {
GeoPoint.toPoint(
BigDecimal(geoCtx.geo_uri().lat().getText),
BigDecimal(geoCtx.geo_uri().lon().getText()),
Option(geoCtx.geo_uri().alt()).map(a => BigDecimal(a.getText))
TacklerReal(geoCtx.geo_uri().lat().getText),
TacklerReal(geoCtx.geo_uri().lon().getText()),
Option(geoCtx.geo_uri().alt()).map(a => TacklerReal(a.getText))
) match {
case Success(g) => g
case Failure(ex) => {
......
......@@ -16,12 +16,13 @@
*/
package fi.e257.tackler.report
import io.circe._
import io.circe.syntax._
import fi.e257.tackler.api.{BalanceItem, BalanceReport, Delta, OrderByDelta}
import fi.e257.tackler.core._
import fi.e257.tackler.math.TacklerReal
import fi.e257.tackler.model.{BalanceTreeNode, TxnData}
import io.circe._
import io.circe.syntax._
abstract class BalanceReporterLike(cfg: ReportConfiguration) extends ReportLike(cfg) {
......@@ -31,7 +32,7 @@ abstract class BalanceReporterLike(cfg: ReportConfiguration) extends ReportLike(
* param f, select which balance sum type to use, account or accountTree
* return max needed width of selected balance sum type
*/
def getMaxSumLen()(f: (BalanceTreeNode => BigDecimal)): Int = {
def getMaxSumLen()(f: (BalanceTreeNode => TacklerReal)): Int = {
balance.bal.map(b => ("% " + getScaleFormat(f(b))).format(f(b)).length).foldLeft(0)(math.max)
}
......
......@@ -18,6 +18,7 @@ package fi.e257.tackler.report
import cats.implicits._
import fi.e257.tackler.api.TxnTS
import fi.e257.tackler.core._
import fi.e257.tackler.math._
import fi.e257.tackler.model.TxnData
class EquityExporter(val settings: Settings) extends ExporterLike {
......@@ -50,7 +51,7 @@ class EquityExporter(val settings: Settings) extends ExporterLike {
.groupBy(b => b.acctn.commStr)
.toSeq.sortBy({ case (commStr, _) => commStr }) // Scala 2.12 vs. 2.13: fix order sorting by commodity
.flatMap({ case (commStr, bs) =>
val eqBalRow = if (bs.map(b => b.accountSum).sum === 0.0) {
val eqBalRow = if (bs.map(b => b.accountSum).realSum.isZero) {
Nil
} else {
List(" " + "Equity:Balance")
......
......@@ -16,9 +16,9 @@
*/
package fi.e257.tackler.report
import io.circe.{Json, Printer}
import fi.e257.tackler.math.TacklerReal
import fi.e257.tackler.model.TxnData
import io.circe.{Json, Printer}
abstract class ReportLike(cfg: ReportConfiguration) extends OutputLike {
......@@ -46,7 +46,7 @@ abstract class ReportLike(cfg: ReportConfiguration) extends OutputLike {
* @param v value to be formatted
* @return decimal part of format string (e.g. ".2f")
*/
def getScaleFormat(v: BigDecimal): String = {
def getScaleFormat(v: TacklerReal): String = {
".%df".format(
if (v.scale <= minScale) {
minScale
......@@ -65,7 +65,7 @@ abstract class ReportLike(cfg: ReportConfiguration) extends OutputLike {
* @param v value
* @return formatted value without filling
*/
def scaleFormat(v: BigDecimal): String = {
def scaleFormat(v: TacklerReal): String = {
("%" + getScaleFormat(v)).format(v)
}
......@@ -77,7 +77,7 @@ abstract class ReportLike(cfg: ReportConfiguration) extends OutputLike {
* @param v value
* @return format string (e.g. "% 12.2f")
*/
def getFillFormat(width: Int, v: BigDecimal): String = {
def getFillFormat(width: Int, v: TacklerReal): String = {
"% " + "%d".format(width) + getScaleFormat(v)
}
......@@ -89,7 +89,7 @@ abstract class ReportLike(cfg: ReportConfiguration) extends OutputLike {
* @param v value to be formatted
* @return value formatted as string
*/
def fillFormat(width: Int, v: BigDecimal): String = {
def fillFormat(width: Int, v: TacklerReal): String = {
getFillFormat(width, v).format(v)
}
......
......@@ -19,14 +19,14 @@ package fi.e257.tackler.filter
import java.time.ZonedDateTime
import java.util.UUID
import io.circe.syntax._
import io.circe.parser.decode
import org.scalatest.FunSpecLike
import fi.e257.tackler.api._
import fi.e257.tackler.core.Settings
import fi.e257.tackler.math.TacklerReal
import fi.e257.tackler.model.TxnData
import fi.e257.tackler.parser.TacklerTxns
import io.circe.parser.decode
import io.circe.syntax._
import org.scalatest.FunSpecLike
class TxnFilterJsonTest extends TxnFilterSpec with FunSpecLike {
val filterJsonStr =
......@@ -352,7 +352,7 @@ class TxnFilterJsonTest extends TxnFilterSpec with FunSpecLike {
TxnFilterPostingAmountEqual("posting:amount:equal", 1),
TxnFilterPostingAmountLess("posting.amount:less", 2),
TxnFilterPostingAmountGreater("posting.amount:greater",
BigDecimal("123456789123456789.012345678901234567890123456789")),
TacklerReal("123456789123456789.012345678901234567890123456789")),
TxnFilterPostingCommodity("posting.commodity"),
TxnFilterPostingComment("posting.comment"),
)),
......
......@@ -16,11 +16,11 @@
*/
package fi.e257.tackler.filter
import org.scalatest.FlatSpecLike
import fi.e257.tackler.api._
import fi.e257.tackler.core.Settings
import fi.e257.tackler.math.TacklerReal
import fi.e257.tackler.parser.TacklerTxns
import org.scalatest.FlatSpecLike
class TxnFilterPostingTest extends TxnFilterSpec with FlatSpecLike {
val tt = new TacklerTxns(Settings())
......@@ -119,7 +119,7 @@ class TxnFilterPostingTest extends TxnFilterSpec with FlatSpecLike {
* test: de72fb67-14a7-4032-b2c2-b1049ecd0c35
*/
it must "filter by posting amount (exact)" in {
val txnFilter = TxnFilterPostingAmountEqual("e:.*", BigDecimal(1.000000001))
val txnFilter = TxnFilterPostingAmountEqual("e:.*", TacklerReal(1.000000001))
val txnData = txnsAll.filter(TxnFilterDefinition(txnFilter))
......@@ -131,7 +131,7 @@ class TxnFilterPostingTest extends TxnFilterSpec with FlatSpecLike {
* test: 315d5ac3-28cf-417e-98bb-b738f209f5da
*/
it must "filter by posting amount (less)" in {
val txnFilter = TxnFilterPostingAmountLess("e:.*", BigDecimal(2))
val txnFilter = TxnFilterPostingAmountLess("e:.*", TacklerReal(2))
val txnData = txnsAll.filter(TxnFilterDefinition(txnFilter))
......@@ -144,7 +144,7 @@ class TxnFilterPostingTest extends TxnFilterSpec with FlatSpecLike {
* test: b94b99d7-acfa-4a4b-871f-c1b6282738ff
*/
it must "filter by posting amount (greater)" in {
val txnFilter = TxnFilterPostingAmountGreater("e:.*", BigDecimal(2))
val txnFilter = TxnFilterPostingAmountGreater("e:.*", TacklerReal(2))
val txnData = txnsAll.filter(TxnFilterDefinition(txnFilter))
......
......@@ -14,41 +14,27 @@
* limitations under the License.
*
*/
package fi.e257.tackler.report
package fi.e257.tackler.math
import fi.e257.tackler.model.TxnData
import io.circe.Json
import org.scalatest.FunSpec
class ReportLikeBigDecimalTest extends FunSpec {
class DefaultReportSettings extends ReportConfiguration {
override val minScale = 0
override val maxScale = 25
}
import java.math.MathContext
class Frmt(val name: String, cfg: ReportConfiguration) extends ReportLike(cfg) {
override def writeReport(formats: Formats, txns: TxnData): Unit = ???
override def jsonReport(txnData: TxnData): Json = ???
}
import org.scalatest.FunSpec
val defaultFrmt = new Frmt("", new DefaultReportSettings())
class TacklerRealTest extends FunSpec {
val bd1 = TacklerReal("1000000000000000000000000.1")
val bd2 = TacklerReal("2000000000000000000000.0002")
val bd3 = TacklerReal("3000000000000000000.0000003")
val bd4 = TacklerReal("4000000000000000.0000000004")
val bd5 = TacklerReal("5000000000000.0000000000005")
val bd6 = TacklerReal("6000000000.0000000000000006")
val bd7 = TacklerReal("7000000.0000000000000000007")
val bd8 = TacklerReal("8000.0000000000000000000008")
val bd9 = TacklerReal("9.0000000000000000000000009")
val bd1 = scala.math.BigDecimal("1000000000000000000000000.1")
val bd2 = scala.math.BigDecimal("2000000000000000000000.0002")
val bd3 = scala.math.BigDecimal("3000000000000000000.0000003")
val bd4 = scala.math.BigDecimal("4000000000000000.0000000004")
val bd5 = scala.math.BigDecimal("5000000000000.0000000000005")
val bd6 = scala.math.BigDecimal("6000000000.0000000000000006")
val bd7 = scala.math.BigDecimal("7000000.0000000000000000007")
val bd8 = scala.math.BigDecimal("8000.0000000000000000000008")
val bd9 = scala.math.BigDecimal("9.0000000000000000000000009")
val bdSumStr = "1002003004005006007008009.1002003004005006007008009"
/**
* Scala 2.13.0 breaks BigDecimal (e.g. this will fail with 2.13.0)
*/
describe("Check BigDecimal") {
describe("TacklerReal") {
it ("ok: bd9") {
val v = bd9
......@@ -56,7 +42,7 @@ class ReportLikeBigDecimalTest extends FunSpec {
assert(v.scale === 25)
assert(v === scala.math.BigDecimal(res))
assert(defaultFrmt.scaleFormat(v) === res)
assert(v.toString() === res)
}
it ("ok: bd8 + bd9") {
......@@ -65,7 +51,7 @@ class ReportLikeBigDecimalTest extends FunSpec {
assert(v.scale === 25)
assert(v === scala.math.BigDecimal(res))
assert(defaultFrmt.scaleFormat(v) === res)
assert(v.toString() === res)
}
it ("ok: bd7 + bd8 + bd9") {
......@@ -74,7 +60,7 @@ class ReportLikeBigDecimalTest extends FunSpec {
assert(v.scale === 25)
assert(v === scala.math.BigDecimal(res))
assert(defaultFrmt.scaleFormat(v) === res)
assert(v.toString() === res)
}
it ("ok: bd6 + bd7 + bd8 + bd9") {
......@@ -83,7 +69,7 @@ class ReportLikeBigDecimalTest extends FunSpec {
assert(v.scale === 25)
assert(v === scala.math.BigDecimal(res))
assert(defaultFrmt.scaleFormat(v) === res)
assert(v.toString() === res)
}
it ("ok: bd5 + bd6 + bd7 + bd8 + bd9") {
......@@ -92,7 +78,7 @@ class ReportLikeBigDecimalTest extends FunSpec {
assert(v.scale === 25)
assert(v === scala.math.BigDecimal(res))
assert(defaultFrmt.scaleFormat(v) === res)
assert(v.toString() === res)
}
it ("ok: bd4 + bd5 + bd6 + bd7 + bd8 + bd9") {
......@@ -101,7 +87,6 @@ class ReportLikeBigDecimalTest extends FunSpec {
assert(v.scale === 25)
assert(v === scala.math.BigDecimal(res))
assert(defaultFrmt.scaleFormat(v) === res)
}
it ("ok: bd3 + bd4 + bd5 + bd6 + bd7 + bd8 + bd9") {
......@@ -110,7 +95,7 @@ class ReportLikeBigDecimalTest extends FunSpec {
assert(v.scale === 25)
assert(v === scala.math.BigDecimal(res))
assert(defaultFrmt.scaleFormat(v) === res)
assert(v.toString() === res)
}
it ("ok: bd2 + bd3 + bd4 + bd5 + bd6 + bd7 + bd8 + bd9") {
......@@ -119,16 +104,114 @@ class ReportLikeBigDecimalTest extends FunSpec {
assert(v.scale === 25)
assert(v === scala.math.BigDecimal(res))
assert(defaultFrmt.scaleFormat(v) === res)
assert(v.toString() === res)
}
it ("ok: bd1 + bd2 + bd3 + bd4 + bd5 + bd6 + bd7 + bd8 + bd9") {