quantity_test.go 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package resource
  14. import (
  15. "encoding/json"
  16. "math/rand"
  17. "strings"
  18. "testing"
  19. "unicode"
  20. fuzz "github.com/google/gofuzz"
  21. "github.com/spf13/pflag"
  22. inf "gopkg.in/inf.v0"
  23. )
  24. var (
  25. testQuantityFlag = QuantityFlag("quantityFlag", "1M", "dummy flag for testing the quantity flag mechanism")
  26. )
  27. var useInfDec bool
  28. func amount(i int64, exponent int) infDecAmount {
  29. // See the below test-- scale is the negative of an exponent.
  30. return infDecAmount{inf.NewDec(i, inf.Scale(-exponent))}
  31. }
  32. func dec(i int64, exponent int) infDecAmount {
  33. // See the below test-- scale is the negative of an exponent.
  34. return infDecAmount{inf.NewDec(i, inf.Scale(-exponent))}
  35. }
  36. func decQuantity(i int64, exponent int, format Format) Quantity {
  37. return Quantity{d: dec(i, exponent), Format: format}
  38. }
  39. func intQuantity(i int64, exponent Scale, format Format) Quantity {
  40. return Quantity{i: int64Amount{value: i, scale: exponent}, Format: format}
  41. }
  42. func TestDec(t *testing.T) {
  43. table := []struct {
  44. got infDecAmount
  45. expect string
  46. }{
  47. {dec(1, 0), "1"},
  48. {dec(1, 1), "10"},
  49. {dec(5, 2), "500"},
  50. {dec(8, 3), "8000"},
  51. {dec(2, 0), "2"},
  52. {dec(1, -1), "0.1"},
  53. {dec(3, -2), "0.03"},
  54. {dec(4, -3), "0.004"},
  55. }
  56. for _, item := range table {
  57. if e, a := item.expect, item.got.Dec.String(); e != a {
  58. t.Errorf("expected %v, got %v", e, a)
  59. }
  60. }
  61. }
  62. // TestQuantityParseZero ensures that when a 0 quantity is passed, its string value is 0
  63. func TestQuantityParseZero(t *testing.T) {
  64. zero := MustParse("0")
  65. if expected, actual := "0", zero.String(); expected != actual {
  66. t.Errorf("Expected %v, actual %v", expected, actual)
  67. }
  68. }
  69. // TestQuantityAddZeroPreservesSuffix verifies that a suffix is preserved
  70. // independent of the order of operations when adding a zero and non-zero val
  71. func TestQuantityAddZeroPreservesSuffix(t *testing.T) {
  72. testValues := []string{"100m", "1Gi"}
  73. zero := MustParse("0")
  74. for _, testValue := range testValues {
  75. value := MustParse(testValue)
  76. v1 := *value.Copy()
  77. // ensure non-zero + zero = non-zero (suffix preserved)
  78. v1.Add(zero)
  79. // ensure zero + non-zero = non-zero (suffix preserved)
  80. v2 := *zero.Copy()
  81. v2.Add(value)
  82. if v1.String() != testValue {
  83. t.Errorf("Expected %v, actual %v", testValue, v1.String())
  84. continue
  85. }
  86. if v2.String() != testValue {
  87. t.Errorf("Expected %v, actual %v", testValue, v2.String())
  88. }
  89. }
  90. }
  91. // TestQuantitySubZeroPreservesSuffix verifies that a suffix is preserved
  92. // independent of the order of operations when subtracting a zero and non-zero val
  93. func TestQuantitySubZeroPreservesSuffix(t *testing.T) {
  94. testValues := []string{"100m", "1Gi"}
  95. zero := MustParse("0")
  96. for _, testValue := range testValues {
  97. value := MustParse(testValue)
  98. v1 := *value.Copy()
  99. // ensure non-zero - zero = non-zero (suffix preserved)
  100. v1.Sub(zero)
  101. // ensure we preserved the input value
  102. if v1.String() != testValue {
  103. t.Errorf("Expected %v, actual %v", testValue, v1.String())
  104. }
  105. // ensure zero - non-zero = -non-zero (suffix preserved)
  106. v2 := *zero.Copy()
  107. v2.Sub(value)
  108. negVal := *value.Copy()
  109. negVal.Neg()
  110. if v2.String() != negVal.String() {
  111. t.Errorf("Expected %v, actual %v", negVal.String(), v2.String())
  112. }
  113. }
  114. }
  115. // Verifies that you get 0 as canonical value if internal value is 0, and not 0<suffix>
  116. func TestQuantityCanocicalizeZero(t *testing.T) {
  117. val := MustParse("1000m")
  118. val.i.Sub(int64Amount{value: 1})
  119. zero := Quantity{i: val.i, Format: DecimalSI}
  120. if expected, actual := "0", zero.String(); expected != actual {
  121. t.Errorf("Expected %v, actual %v", expected, actual)
  122. }
  123. }
  124. func TestQuantityCmp(t *testing.T) {
  125. table := []struct {
  126. x string
  127. y string
  128. expect int
  129. }{
  130. {"0", "0", 0},
  131. {"100m", "50m", 1},
  132. {"50m", "100m", -1},
  133. {"10000T", "100Gi", 1},
  134. }
  135. for _, testCase := range table {
  136. q1 := MustParse(testCase.x)
  137. q2 := MustParse(testCase.y)
  138. if result := q1.Cmp(q2); result != testCase.expect {
  139. t.Errorf("X: %v, Y: %v, Expected: %v, Actual: %v", testCase.x, testCase.y, testCase.expect, result)
  140. }
  141. }
  142. nils := []struct {
  143. x *inf.Dec
  144. y *inf.Dec
  145. expect int
  146. }{
  147. {dec(0, 0).Dec, dec(0, 0).Dec, 0},
  148. {nil, dec(0, 0).Dec, 0},
  149. {dec(0, 0).Dec, nil, 0},
  150. {nil, nil, 0},
  151. {nil, dec(10, 0).Dec, -1},
  152. {nil, dec(-10, 0).Dec, 1},
  153. {dec(10, 0).Dec, nil, 1},
  154. {dec(-10, 0).Dec, nil, -1},
  155. }
  156. for _, nilCase := range nils {
  157. q1 := Quantity{d: infDecAmount{nilCase.x}, Format: DecimalSI}
  158. q2 := Quantity{d: infDecAmount{nilCase.y}, Format: DecimalSI}
  159. if result := q1.Cmp(q2); result != nilCase.expect {
  160. t.Errorf("X: %v, Y: %v, Expected: %v, Actual: %v", nilCase.x, nilCase.y, nilCase.expect, result)
  161. }
  162. }
  163. }
  164. func TestParseQuantityString(t *testing.T) {
  165. table := []struct {
  166. input string
  167. positive bool
  168. value string
  169. num, denom, suffix string
  170. }{
  171. {"0.025Ti", true, "0.025", "0", "025", "Ti"},
  172. {"1.025Ti", true, "1.025", "1", "025", "Ti"},
  173. {"-1.025Ti", false, "-1.025", "1", "025", "Ti"},
  174. {".", true, ".", "0", "", ""},
  175. {"-.", false, "-.", "0", "", ""},
  176. {"1E-3", true, "1", "1", "", "E-3"},
  177. }
  178. for _, test := range table {
  179. positive, value, num, denom, suffix, err := parseQuantityString(test.input)
  180. if err != nil {
  181. t.Errorf("%s: error: %v", test.input, err)
  182. continue
  183. }
  184. if positive != test.positive || value != test.value || num != test.num || denom != test.denom || suffix != test.suffix {
  185. t.Errorf("%s: unmatched: %t %q %q %q %q", test.input, positive, value, num, denom, suffix)
  186. }
  187. }
  188. }
  189. func TestQuantityParse(t *testing.T) {
  190. if _, err := ParseQuantity(""); err == nil {
  191. t.Errorf("expected empty string to return error")
  192. }
  193. table := []struct {
  194. input string
  195. expect Quantity
  196. }{
  197. {"0", decQuantity(0, 0, DecimalSI)},
  198. {"0n", decQuantity(0, 0, DecimalSI)},
  199. {"0u", decQuantity(0, 0, DecimalSI)},
  200. {"0m", decQuantity(0, 0, DecimalSI)},
  201. {"0Ki", decQuantity(0, 0, BinarySI)},
  202. {"0k", decQuantity(0, 0, DecimalSI)},
  203. {"0Mi", decQuantity(0, 0, BinarySI)},
  204. {"0M", decQuantity(0, 0, DecimalSI)},
  205. {"0Gi", decQuantity(0, 0, BinarySI)},
  206. {"0G", decQuantity(0, 0, DecimalSI)},
  207. {"0Ti", decQuantity(0, 0, BinarySI)},
  208. {"0T", decQuantity(0, 0, DecimalSI)},
  209. // Quantity less numbers are allowed
  210. {"1", decQuantity(1, 0, DecimalSI)},
  211. // Binary suffixes
  212. {"1Ki", decQuantity(1024, 0, BinarySI)},
  213. {"8Ki", decQuantity(8*1024, 0, BinarySI)},
  214. {"7Mi", decQuantity(7*1024*1024, 0, BinarySI)},
  215. {"6Gi", decQuantity(6*1024*1024*1024, 0, BinarySI)},
  216. {"5Ti", decQuantity(5*1024*1024*1024*1024, 0, BinarySI)},
  217. {"4Pi", decQuantity(4*1024*1024*1024*1024*1024, 0, BinarySI)},
  218. {"3Ei", decQuantity(3*1024*1024*1024*1024*1024*1024, 0, BinarySI)},
  219. {"10Ti", decQuantity(10*1024*1024*1024*1024, 0, BinarySI)},
  220. {"100Ti", decQuantity(100*1024*1024*1024*1024, 0, BinarySI)},
  221. // Decimal suffixes
  222. {"5n", decQuantity(5, -9, DecimalSI)},
  223. {"4u", decQuantity(4, -6, DecimalSI)},
  224. {"3m", decQuantity(3, -3, DecimalSI)},
  225. {"9", decQuantity(9, 0, DecimalSI)},
  226. {"8k", decQuantity(8, 3, DecimalSI)},
  227. {"50k", decQuantity(5, 4, DecimalSI)},
  228. {"7M", decQuantity(7, 6, DecimalSI)},
  229. {"6G", decQuantity(6, 9, DecimalSI)},
  230. {"5T", decQuantity(5, 12, DecimalSI)},
  231. {"40T", decQuantity(4, 13, DecimalSI)},
  232. {"300T", decQuantity(3, 14, DecimalSI)},
  233. {"2P", decQuantity(2, 15, DecimalSI)},
  234. {"1E", decQuantity(1, 18, DecimalSI)},
  235. // Decimal exponents
  236. {"1E-3", decQuantity(1, -3, DecimalExponent)},
  237. {"1e3", decQuantity(1, 3, DecimalExponent)},
  238. {"1E6", decQuantity(1, 6, DecimalExponent)},
  239. {"1e9", decQuantity(1, 9, DecimalExponent)},
  240. {"1E12", decQuantity(1, 12, DecimalExponent)},
  241. {"1e15", decQuantity(1, 15, DecimalExponent)},
  242. {"1E18", decQuantity(1, 18, DecimalExponent)},
  243. // Nonstandard but still parsable
  244. {"1e14", decQuantity(1, 14, DecimalExponent)},
  245. {"1e13", decQuantity(1, 13, DecimalExponent)},
  246. {"1e3", decQuantity(1, 3, DecimalExponent)},
  247. {"100.035k", decQuantity(100035, 0, DecimalSI)},
  248. // Things that look like floating point
  249. {"0.001", decQuantity(1, -3, DecimalSI)},
  250. {"0.0005k", decQuantity(5, -1, DecimalSI)},
  251. {"0.005", decQuantity(5, -3, DecimalSI)},
  252. {"0.05", decQuantity(5, -2, DecimalSI)},
  253. {"0.5", decQuantity(5, -1, DecimalSI)},
  254. {"0.00050k", decQuantity(5, -1, DecimalSI)},
  255. {"0.00500", decQuantity(5, -3, DecimalSI)},
  256. {"0.05000", decQuantity(5, -2, DecimalSI)},
  257. {"0.50000", decQuantity(5, -1, DecimalSI)},
  258. {"0.5e0", decQuantity(5, -1, DecimalExponent)},
  259. {"0.5e-1", decQuantity(5, -2, DecimalExponent)},
  260. {"0.5e-2", decQuantity(5, -3, DecimalExponent)},
  261. {"0.5e0", decQuantity(5, -1, DecimalExponent)},
  262. {"10.035M", decQuantity(10035, 3, DecimalSI)},
  263. {"1.2e3", decQuantity(12, 2, DecimalExponent)},
  264. {"1.3E+6", decQuantity(13, 5, DecimalExponent)},
  265. {"1.40e9", decQuantity(14, 8, DecimalExponent)},
  266. {"1.53E12", decQuantity(153, 10, DecimalExponent)},
  267. {"1.6e15", decQuantity(16, 14, DecimalExponent)},
  268. {"1.7E18", decQuantity(17, 17, DecimalExponent)},
  269. {"9.01", decQuantity(901, -2, DecimalSI)},
  270. {"8.1k", decQuantity(81, 2, DecimalSI)},
  271. {"7.123456M", decQuantity(7123456, 0, DecimalSI)},
  272. {"6.987654321G", decQuantity(6987654321, 0, DecimalSI)},
  273. {"5.444T", decQuantity(5444, 9, DecimalSI)},
  274. {"40.1T", decQuantity(401, 11, DecimalSI)},
  275. {"300.2T", decQuantity(3002, 11, DecimalSI)},
  276. {"2.5P", decQuantity(25, 14, DecimalSI)},
  277. {"1.01E", decQuantity(101, 16, DecimalSI)},
  278. // Things that saturate/round
  279. {"3.001n", decQuantity(4, -9, DecimalSI)},
  280. {"1.1E-9", decQuantity(2, -9, DecimalExponent)},
  281. {"0.0000000001", decQuantity(1, -9, DecimalSI)},
  282. {"0.0000000005", decQuantity(1, -9, DecimalSI)},
  283. {"0.00000000050", decQuantity(1, -9, DecimalSI)},
  284. {"0.5e-9", decQuantity(1, -9, DecimalExponent)},
  285. {"0.9n", decQuantity(1, -9, DecimalSI)},
  286. {"0.00000012345", decQuantity(124, -9, DecimalSI)},
  287. {"0.00000012354", decQuantity(124, -9, DecimalSI)},
  288. {"9Ei", Quantity{d: maxAllowed, Format: BinarySI}},
  289. {"9223372036854775807Ki", Quantity{d: maxAllowed, Format: BinarySI}},
  290. {"12E", decQuantity(12, 18, DecimalSI)},
  291. // We'll accept fractional binary stuff, too.
  292. {"100.035Ki", decQuantity(10243584, -2, BinarySI)},
  293. {"0.5Mi", decQuantity(.5*1024*1024, 0, BinarySI)},
  294. {"0.05Gi", decQuantity(536870912, -1, BinarySI)},
  295. {"0.025Ti", decQuantity(274877906944, -1, BinarySI)},
  296. // Things written by trolls
  297. {"0.000000000001Ki", decQuantity(2, -9, DecimalSI)}, // rounds up, changes format
  298. {".001", decQuantity(1, -3, DecimalSI)},
  299. {".0001k", decQuantity(100, -3, DecimalSI)},
  300. {"1.", decQuantity(1, 0, DecimalSI)},
  301. {"1.G", decQuantity(1, 9, DecimalSI)},
  302. }
  303. for _, asDec := range []bool{false, true} {
  304. for _, item := range table {
  305. got, err := ParseQuantity(item.input)
  306. if err != nil {
  307. t.Errorf("%v: unexpected error: %v", item.input, err)
  308. continue
  309. }
  310. if asDec {
  311. got.AsDec()
  312. }
  313. if e, a := item.expect, got; e.Cmp(a) != 0 {
  314. t.Errorf("%v: expected %v, got %v", item.input, e.String(), a.String())
  315. }
  316. if e, a := item.expect.Format, got.Format; e != a {
  317. t.Errorf("%v: expected %#v, got %#v", item.input, e, a)
  318. }
  319. if asDec {
  320. if i, ok := got.AsInt64(); i != 0 || ok {
  321. t.Errorf("%v: expected inf.Dec to return false for AsInt64: %d", item.input, i)
  322. }
  323. continue
  324. }
  325. i, ok := item.expect.AsInt64()
  326. if !ok {
  327. continue
  328. }
  329. j, ok := got.AsInt64()
  330. if !ok {
  331. if got.d.Dec == nil && got.i.scale >= 0 {
  332. t.Errorf("%v: is an int64Amount, but can't return AsInt64: %v", item.input, got)
  333. }
  334. continue
  335. }
  336. if i != j {
  337. t.Errorf("%v: expected equivalent representation as int64: %d %d", item.input, i, j)
  338. }
  339. }
  340. for _, item := range table {
  341. got, err := ParseQuantity(item.input)
  342. if err != nil {
  343. t.Errorf("%v: unexpected error: %v", item.input, err)
  344. continue
  345. }
  346. if asDec {
  347. got.AsDec()
  348. }
  349. // verify that we can decompose the input and get the same result by building up from the base.
  350. positive, _, num, denom, suffix, err := parseQuantityString(item.input)
  351. if err != nil {
  352. t.Errorf("%v: unexpected error: %v", item.input, err)
  353. continue
  354. }
  355. if got.Sign() >= 0 && !positive || got.Sign() < 0 && positive {
  356. t.Errorf("%v: positive was incorrect: %t", item.input, positive)
  357. continue
  358. }
  359. var value string
  360. if !positive {
  361. value = "-"
  362. }
  363. value += num
  364. if len(denom) > 0 {
  365. value += "." + denom
  366. }
  367. value += suffix
  368. if len(value) == 0 {
  369. t.Errorf("%v: did not parse correctly, %q %q %q", item.input, num, denom, suffix)
  370. }
  371. expected, err := ParseQuantity(value)
  372. if err != nil {
  373. t.Errorf("%v: unexpected error for %s: %v", item.input, value, err)
  374. continue
  375. }
  376. if expected.Cmp(got) != 0 {
  377. t.Errorf("%v: not the same as %s", item.input, value)
  378. continue
  379. }
  380. }
  381. // Try the negative version of everything
  382. desired := &inf.Dec{}
  383. expect := Quantity{d: infDecAmount{Dec: desired}}
  384. for _, item := range table {
  385. got, err := ParseQuantity("-" + strings.TrimLeftFunc(item.input, unicode.IsSpace))
  386. if err != nil {
  387. t.Errorf("-%v: unexpected error: %v", item.input, err)
  388. continue
  389. }
  390. if asDec {
  391. got.AsDec()
  392. }
  393. expected := item.expect
  394. desired.Neg(expected.AsDec())
  395. if e, a := expect, got; e.Cmp(a) != 0 {
  396. t.Errorf("%v: expected %s, got %s", item.input, e.String(), a.String())
  397. }
  398. if e, a := expected.Format, got.Format; e != a {
  399. t.Errorf("%v: expected %#v, got %#v", item.input, e, a)
  400. }
  401. }
  402. // Try everything with an explicit +
  403. for _, item := range table {
  404. got, err := ParseQuantity("+" + strings.TrimLeftFunc(item.input, unicode.IsSpace))
  405. if err != nil {
  406. t.Errorf("-%v: unexpected error: %v", item.input, err)
  407. continue
  408. }
  409. if asDec {
  410. got.AsDec()
  411. }
  412. if e, a := item.expect, got; e.Cmp(a) != 0 {
  413. t.Errorf("%v(%t): expected %s, got %s", item.input, asDec, e.String(), a.String())
  414. }
  415. if e, a := item.expect.Format, got.Format; e != a {
  416. t.Errorf("%v: expected %#v, got %#v", item.input, e, a)
  417. }
  418. }
  419. }
  420. invalid := []string{
  421. "1.1.M",
  422. "1+1.0M",
  423. "0.1mi",
  424. "0.1am",
  425. "aoeu",
  426. ".5i",
  427. "1i",
  428. "-3.01i",
  429. "-3.01e-",
  430. // trailing whitespace is forbidden
  431. " 1",
  432. "1 ",
  433. }
  434. for _, item := range invalid {
  435. _, err := ParseQuantity(item)
  436. if err == nil {
  437. t.Errorf("%v parsed unexpectedly", item)
  438. }
  439. }
  440. }
  441. func TestQuantityRoundUp(t *testing.T) {
  442. table := []struct {
  443. in string
  444. scale Scale
  445. expect Quantity
  446. ok bool
  447. }{
  448. {"9.01", -3, decQuantity(901, -2, DecimalSI), true},
  449. {"9.01", -2, decQuantity(901, -2, DecimalSI), true},
  450. {"9.01", -1, decQuantity(91, -1, DecimalSI), false},
  451. {"9.01", 0, decQuantity(10, 0, DecimalSI), false},
  452. {"9.01", 1, decQuantity(10, 0, DecimalSI), false},
  453. {"9.01", 2, decQuantity(100, 0, DecimalSI), false},
  454. {"-9.01", -3, decQuantity(-901, -2, DecimalSI), true},
  455. {"-9.01", -2, decQuantity(-901, -2, DecimalSI), true},
  456. {"-9.01", -1, decQuantity(-91, -1, DecimalSI), false},
  457. {"-9.01", 0, decQuantity(-10, 0, DecimalSI), false},
  458. {"-9.01", 1, decQuantity(-10, 0, DecimalSI), false},
  459. {"-9.01", 2, decQuantity(-100, 0, DecimalSI), false},
  460. }
  461. for _, asDec := range []bool{false, true} {
  462. for _, item := range table {
  463. got, err := ParseQuantity(item.in)
  464. if err != nil {
  465. t.Fatalf("unexpected error: %v", err)
  466. }
  467. expect := *item.expect.Copy()
  468. if asDec {
  469. got.AsDec()
  470. }
  471. if ok := got.RoundUp(item.scale); ok != item.ok {
  472. t.Errorf("%s(%d,%t): unexpected ok: %t", item.in, item.scale, asDec, ok)
  473. }
  474. if got.Cmp(expect) != 0 {
  475. t.Errorf("%s(%d,%t): unexpected round: %s vs %s", item.in, item.scale, asDec, got.String(), expect.String())
  476. }
  477. }
  478. }
  479. }
  480. func TestQuantityCmpInt64AndDec(t *testing.T) {
  481. table := []struct {
  482. a, b Quantity
  483. cmp int
  484. }{
  485. {intQuantity(901, -2, DecimalSI), intQuantity(901, -2, DecimalSI), 0},
  486. {intQuantity(90, -1, DecimalSI), intQuantity(901, -2, DecimalSI), -1},
  487. {intQuantity(901, -2, DecimalSI), intQuantity(900, -2, DecimalSI), 1},
  488. {intQuantity(0, 0, DecimalSI), intQuantity(0, 0, DecimalSI), 0},
  489. {intQuantity(0, 1, DecimalSI), intQuantity(0, -1, DecimalSI), 0},
  490. {intQuantity(0, -1, DecimalSI), intQuantity(0, 1, DecimalSI), 0},
  491. {intQuantity(800, -3, DecimalSI), intQuantity(1, 0, DecimalSI), -1},
  492. {intQuantity(800, -3, DecimalSI), intQuantity(79, -2, DecimalSI), 1},
  493. {intQuantity(mostPositive, 0, DecimalSI), intQuantity(1, -1, DecimalSI), 1},
  494. {intQuantity(mostPositive, 1, DecimalSI), intQuantity(1, 0, DecimalSI), 1},
  495. {intQuantity(mostPositive, 1, DecimalSI), intQuantity(1, 1, DecimalSI), 1},
  496. {intQuantity(mostPositive, 1, DecimalSI), intQuantity(0, 1, DecimalSI), 1},
  497. {intQuantity(mostPositive, -16, DecimalSI), intQuantity(1, 3, DecimalSI), -1},
  498. {intQuantity(mostNegative, 0, DecimalSI), intQuantity(0, 0, DecimalSI), -1},
  499. {intQuantity(mostNegative, -18, DecimalSI), intQuantity(-1, 0, DecimalSI), -1},
  500. {intQuantity(mostNegative, -19, DecimalSI), intQuantity(-1, 0, DecimalSI), 1},
  501. {intQuantity(1*1000000*1000000*1000000, -17, DecimalSI), intQuantity(1, 1, DecimalSI), 0},
  502. {intQuantity(1*1000000*1000000*1000000, -17, DecimalSI), intQuantity(-10, 0, DecimalSI), 1},
  503. {intQuantity(-1*1000000*1000000*1000000, -17, DecimalSI), intQuantity(-10, 0, DecimalSI), 0},
  504. {intQuantity(1*1000000*1000000*1000000, -17, DecimalSI), intQuantity(1, 0, DecimalSI), 1},
  505. {intQuantity(1*1000000*1000000*1000000+1, -17, DecimalSI), intQuantity(1, 1, DecimalSI), 1},
  506. {intQuantity(1*1000000*1000000*1000000-1, -17, DecimalSI), intQuantity(1, 1, DecimalSI), -1},
  507. }
  508. for _, item := range table {
  509. if cmp := item.a.Cmp(item.b); cmp != item.cmp {
  510. t.Errorf("%#v: unexpected Cmp: %d", item, cmp)
  511. }
  512. if cmp := item.b.Cmp(item.a); cmp != -item.cmp {
  513. t.Errorf("%#v: unexpected inverted Cmp: %d", item, cmp)
  514. }
  515. }
  516. for _, item := range table {
  517. a, b := *item.a.Copy(), *item.b.Copy()
  518. a.AsDec()
  519. if cmp := a.Cmp(b); cmp != item.cmp {
  520. t.Errorf("%#v: unexpected Cmp: %d", item, cmp)
  521. }
  522. if cmp := b.Cmp(a); cmp != -item.cmp {
  523. t.Errorf("%#v: unexpected inverted Cmp: %d", item, cmp)
  524. }
  525. }
  526. for _, item := range table {
  527. a, b := *item.a.Copy(), *item.b.Copy()
  528. b.AsDec()
  529. if cmp := a.Cmp(b); cmp != item.cmp {
  530. t.Errorf("%#v: unexpected Cmp: %d", item, cmp)
  531. }
  532. if cmp := b.Cmp(a); cmp != -item.cmp {
  533. t.Errorf("%#v: unexpected inverted Cmp: %d", item, cmp)
  534. }
  535. }
  536. for _, item := range table {
  537. a, b := *item.a.Copy(), *item.b.Copy()
  538. a.AsDec()
  539. b.AsDec()
  540. if cmp := a.Cmp(b); cmp != item.cmp {
  541. t.Errorf("%#v: unexpected Cmp: %d", item, cmp)
  542. }
  543. if cmp := b.Cmp(a); cmp != -item.cmp {
  544. t.Errorf("%#v: unexpected inverted Cmp: %d", item, cmp)
  545. }
  546. }
  547. }
  548. func TestQuantityNeg(t *testing.T) {
  549. table := []struct {
  550. a Quantity
  551. out string
  552. }{
  553. {intQuantity(901, -2, DecimalSI), "-9010m"},
  554. {decQuantity(901, -2, DecimalSI), "-9010m"},
  555. }
  556. for i, item := range table {
  557. out := *item.a.Copy()
  558. out.Neg()
  559. if out.Cmp(item.a) == 0 {
  560. t.Errorf("%d: negating an item should not mutate the source: %s", i, out.String())
  561. }
  562. if out.String() != item.out {
  563. t.Errorf("%d: negating did not equal exact value: %s", i, out.String())
  564. }
  565. }
  566. }
  567. func TestQuantityString(t *testing.T) {
  568. table := []struct {
  569. in Quantity
  570. expect string
  571. alternate string
  572. }{
  573. {decQuantity(1024*1024*1024, 0, BinarySI), "1Gi", "1024Mi"},
  574. {decQuantity(300*1024*1024, 0, BinarySI), "300Mi", "307200Ki"},
  575. {decQuantity(6*1024, 0, BinarySI), "6Ki", ""},
  576. {decQuantity(1001*1024*1024*1024, 0, BinarySI), "1001Gi", "1025024Mi"},
  577. {decQuantity(1024*1024*1024*1024, 0, BinarySI), "1Ti", "1024Gi"},
  578. {decQuantity(5, 0, BinarySI), "5", "5000m"},
  579. {decQuantity(500, -3, BinarySI), "500m", "0.5"},
  580. {decQuantity(1, 9, DecimalSI), "1G", "1000M"},
  581. {decQuantity(1000, 6, DecimalSI), "1G", "0.001T"},
  582. {decQuantity(1000000, 3, DecimalSI), "1G", ""},
  583. {decQuantity(1000000000, 0, DecimalSI), "1G", ""},
  584. {decQuantity(1, -3, DecimalSI), "1m", "1000u"},
  585. {decQuantity(80, -3, DecimalSI), "80m", ""},
  586. {decQuantity(1080, -3, DecimalSI), "1080m", "1.08"},
  587. {decQuantity(108, -2, DecimalSI), "1080m", "1080000000n"},
  588. {decQuantity(10800, -4, DecimalSI), "1080m", ""},
  589. {decQuantity(300, 6, DecimalSI), "300M", ""},
  590. {decQuantity(1, 12, DecimalSI), "1T", ""},
  591. {decQuantity(1234567, 6, DecimalSI), "1234567M", ""},
  592. {decQuantity(1234567, -3, BinarySI), "1234567m", ""},
  593. {decQuantity(3, 3, DecimalSI), "3k", ""},
  594. {decQuantity(1025, 0, BinarySI), "1025", ""},
  595. {decQuantity(0, 0, DecimalSI), "0", ""},
  596. {decQuantity(0, 0, BinarySI), "0", ""},
  597. {decQuantity(1, 9, DecimalExponent), "1e9", ".001e12"},
  598. {decQuantity(1, -3, DecimalExponent), "1e-3", "0.001e0"},
  599. {decQuantity(1, -9, DecimalExponent), "1e-9", "1000e-12"},
  600. {decQuantity(80, -3, DecimalExponent), "80e-3", ""},
  601. {decQuantity(300, 6, DecimalExponent), "300e6", ""},
  602. {decQuantity(1, 12, DecimalExponent), "1e12", ""},
  603. {decQuantity(1, 3, DecimalExponent), "1e3", ""},
  604. {decQuantity(3, 3, DecimalExponent), "3e3", ""},
  605. {decQuantity(3, 3, DecimalSI), "3k", ""},
  606. {decQuantity(0, 0, DecimalExponent), "0", "00"},
  607. {decQuantity(1, -9, DecimalSI), "1n", ""},
  608. {decQuantity(80, -9, DecimalSI), "80n", ""},
  609. {decQuantity(1080, -9, DecimalSI), "1080n", ""},
  610. {decQuantity(108, -8, DecimalSI), "1080n", ""},
  611. {decQuantity(10800, -10, DecimalSI), "1080n", ""},
  612. {decQuantity(1, -6, DecimalSI), "1u", ""},
  613. {decQuantity(80, -6, DecimalSI), "80u", ""},
  614. {decQuantity(1080, -6, DecimalSI), "1080u", ""},
  615. }
  616. for _, item := range table {
  617. got := item.in.String()
  618. if e, a := item.expect, got; e != a {
  619. t.Errorf("%#v: expected %v, got %v", item.in, e, a)
  620. }
  621. q, err := ParseQuantity(item.expect)
  622. if err != nil {
  623. t.Errorf("%#v: unexpected error: %v", item.expect, err)
  624. }
  625. if len(q.s) == 0 || q.s != item.expect {
  626. t.Errorf("%#v: did not copy canonical string on parse: %s", item.expect, q.s)
  627. }
  628. if len(item.alternate) == 0 {
  629. continue
  630. }
  631. q, err = ParseQuantity(item.alternate)
  632. if err != nil {
  633. t.Errorf("%#v: unexpected error: %v", item.expect, err)
  634. continue
  635. }
  636. if len(q.s) != 0 {
  637. t.Errorf("%#v: unexpected nested string: %v", item.expect, q.s)
  638. }
  639. if q.String() != item.expect {
  640. t.Errorf("%#v: unexpected alternate canonical: %v", item.expect, q.String())
  641. }
  642. if len(q.s) == 0 || q.s != item.expect {
  643. t.Errorf("%#v: did not set canonical string on ToString: %s", item.expect, q.s)
  644. }
  645. }
  646. desired := &inf.Dec{} // Avoid modifying the values in the table.
  647. for _, item := range table {
  648. if item.in.Cmp(Quantity{}) == 0 {
  649. // Don't expect it to print "-0" ever
  650. continue
  651. }
  652. q := item.in
  653. q.d = infDecAmount{desired.Neg(q.AsDec())}
  654. if e, a := "-"+item.expect, q.String(); e != a {
  655. t.Errorf("%#v: expected %v, got %v", item.in, e, a)
  656. }
  657. }
  658. }
  659. func TestQuantityParseEmit(t *testing.T) {
  660. table := []struct {
  661. in string
  662. expect string
  663. }{
  664. {"1Ki", "1Ki"},
  665. {"1Mi", "1Mi"},
  666. {"1Gi", "1Gi"},
  667. {"1024Mi", "1Gi"},
  668. {"1000M", "1G"},
  669. {".001Ki", "1024m"},
  670. {".000001Ki", "1024u"},
  671. {".000000001Ki", "1024n"},
  672. {".000000000001Ki", "2n"},
  673. }
  674. for _, item := range table {
  675. q, err := ParseQuantity(item.in)
  676. if err != nil {
  677. t.Errorf("Couldn't parse %v", item.in)
  678. continue
  679. }
  680. if e, a := item.expect, q.String(); e != a {
  681. t.Errorf("%#v: expected %v, got %v", item.in, e, a)
  682. }
  683. }
  684. for _, item := range table {
  685. q, err := ParseQuantity("-" + item.in)
  686. if err != nil {
  687. t.Errorf("Couldn't parse %v", item.in)
  688. continue
  689. }
  690. if q.Cmp(Quantity{}) == 0 {
  691. continue
  692. }
  693. if e, a := "-"+item.expect, q.String(); e != a {
  694. t.Errorf("%#v: expected %v, got %v (%#v)", item.in, e, a, q.i)
  695. }
  696. }
  697. }
  698. var fuzzer = fuzz.New().Funcs(
  699. func(q *Quantity, c fuzz.Continue) {
  700. q.i = Zero
  701. if c.RandBool() {
  702. q.Format = BinarySI
  703. if c.RandBool() {
  704. dec := &inf.Dec{}
  705. q.d = infDecAmount{Dec: dec}
  706. dec.SetScale(0)
  707. dec.SetUnscaled(c.Int63())
  708. return
  709. }
  710. // Be sure to test cases like 1Mi
  711. dec := &inf.Dec{}
  712. q.d = infDecAmount{Dec: dec}
  713. dec.SetScale(0)
  714. dec.SetUnscaled(c.Int63n(1024) << uint(10*c.Intn(5)))
  715. return
  716. }
  717. if c.RandBool() {
  718. q.Format = DecimalSI
  719. } else {
  720. q.Format = DecimalExponent
  721. }
  722. if c.RandBool() {
  723. dec := &inf.Dec{}
  724. q.d = infDecAmount{Dec: dec}
  725. dec.SetScale(inf.Scale(c.Intn(4)))
  726. dec.SetUnscaled(c.Int63())
  727. return
  728. }
  729. // Be sure to test cases like 1M
  730. dec := &inf.Dec{}
  731. q.d = infDecAmount{Dec: dec}
  732. dec.SetScale(inf.Scale(3 - c.Intn(15)))
  733. dec.SetUnscaled(c.Int63n(1000))
  734. },
  735. )
  736. func TestJSON(t *testing.T) {
  737. for i := 0; i < 500; i++ {
  738. q := &Quantity{}
  739. fuzzer.Fuzz(q)
  740. b, err := json.Marshal(q)
  741. if err != nil {
  742. t.Errorf("error encoding %v: %v", q, err)
  743. continue
  744. }
  745. q2 := &Quantity{}
  746. err = json.Unmarshal(b, q2)
  747. if err != nil {
  748. t.Logf("%d: %s", i, string(b))
  749. t.Errorf("%v: error decoding %v: %v", q, string(b), err)
  750. }
  751. if q2.Cmp(*q) != 0 {
  752. t.Errorf("Expected equal: %v, %v (json was '%v')", q, q2, string(b))
  753. }
  754. }
  755. }
  756. func TestJSONWhitespace(t *testing.T) {
  757. q := Quantity{}
  758. testCases := []struct {
  759. in string
  760. expect string
  761. }{
  762. {`" 1"`, "1"},
  763. {`"1 "`, "1"},
  764. {`1`, "1"},
  765. {` 1`, "1"},
  766. {`1 `, "1"},
  767. {`10`, "10"},
  768. {`-1`, "-1"},
  769. {` -1`, "-1"},
  770. }
  771. for _, test := range testCases {
  772. if err := json.Unmarshal([]byte(test.in), &q); err != nil {
  773. t.Errorf("%q: %v", test.in, err)
  774. }
  775. if q.String() != test.expect {
  776. t.Errorf("unexpected string: %q", q.String())
  777. }
  778. }
  779. }
  780. func TestMilliNewSet(t *testing.T) {
  781. table := []struct {
  782. value int64
  783. format Format
  784. expect string
  785. exact bool
  786. }{
  787. {1, DecimalSI, "1m", true},
  788. {1000, DecimalSI, "1", true},
  789. {1234000, DecimalSI, "1234", true},
  790. {1024, BinarySI, "1024m", false}, // Format changes
  791. {1000000, "invalidFormatDefaultsToExponent", "1e3", true},
  792. {1024 * 1024, BinarySI, "1048576m", false}, // Format changes
  793. }
  794. for _, item := range table {
  795. q := NewMilliQuantity(item.value, item.format)
  796. if e, a := item.expect, q.String(); e != a {
  797. t.Errorf("Expected %v, got %v; %#v", e, a, q)
  798. }
  799. if !item.exact {
  800. continue
  801. }
  802. q2, err := ParseQuantity(q.String())
  803. if err != nil {
  804. t.Errorf("Round trip failed on %v", q)
  805. }
  806. if e, a := item.value, q2.MilliValue(); e != a {
  807. t.Errorf("Expected %v, got %v", e, a)
  808. }
  809. }
  810. for _, item := range table {
  811. q := NewQuantity(0, item.format)
  812. q.SetMilli(item.value)
  813. if e, a := item.expect, q.String(); e != a {
  814. t.Errorf("Set: Expected %v, got %v; %#v", e, a, q)
  815. }
  816. }
  817. }
  818. func TestNewSet(t *testing.T) {
  819. table := []struct {
  820. value int64
  821. format Format
  822. expect string
  823. }{
  824. {1, DecimalSI, "1"},
  825. {1000, DecimalSI, "1k"},
  826. {1234000, DecimalSI, "1234k"},
  827. {1024, BinarySI, "1Ki"},
  828. {1000000, "invalidFormatDefaultsToExponent", "1e6"},
  829. {1024 * 1024, BinarySI, "1Mi"},
  830. }
  831. for _, asDec := range []bool{false, true} {
  832. for _, item := range table {
  833. q := NewQuantity(item.value, item.format)
  834. if asDec {
  835. q.ToDec()
  836. }
  837. if e, a := item.expect, q.String(); e != a {
  838. t.Errorf("Expected %v, got %v; %#v", e, a, q)
  839. }
  840. q2, err := ParseQuantity(q.String())
  841. if err != nil {
  842. t.Errorf("Round trip failed on %v", q)
  843. }
  844. if e, a := item.value, q2.Value(); e != a {
  845. t.Errorf("Expected %v, got %v", e, a)
  846. }
  847. }
  848. for _, item := range table {
  849. q := NewQuantity(0, item.format)
  850. q.Set(item.value)
  851. if asDec {
  852. q.ToDec()
  853. }
  854. if e, a := item.expect, q.String(); e != a {
  855. t.Errorf("Set: Expected %v, got %v; %#v", e, a, q)
  856. }
  857. }
  858. }
  859. }
  860. func TestNewScaledSet(t *testing.T) {
  861. table := []struct {
  862. value int64
  863. scale Scale
  864. expect string
  865. }{
  866. {1, Nano, "1n"},
  867. {1000, Nano, "1u"},
  868. {1, Micro, "1u"},
  869. {1000, Micro, "1m"},
  870. {1, Milli, "1m"},
  871. {1000, Milli, "1"},
  872. {1, 0, "1"},
  873. {0, Nano, "0"},
  874. {0, Micro, "0"},
  875. {0, Milli, "0"},
  876. {0, 0, "0"},
  877. }
  878. for _, item := range table {
  879. q := NewScaledQuantity(item.value, item.scale)
  880. if e, a := item.expect, q.String(); e != a {
  881. t.Errorf("Expected %v, got %v; %#v", e, a, q)
  882. }
  883. q2, err := ParseQuantity(q.String())
  884. if err != nil {
  885. t.Errorf("Round trip failed on %v", q)
  886. }
  887. if e, a := item.value, q2.ScaledValue(item.scale); e != a {
  888. t.Errorf("Expected %v, got %v", e, a)
  889. }
  890. q3 := NewQuantity(0, DecimalSI)
  891. q3.SetScaled(item.value, item.scale)
  892. if q.Cmp(*q3) != 0 {
  893. t.Errorf("Expected %v and %v to be equal", q, q3)
  894. }
  895. }
  896. }
  897. func TestScaledValue(t *testing.T) {
  898. table := []struct {
  899. fromScale Scale
  900. toScale Scale
  901. expected int64
  902. }{
  903. {Nano, Nano, 1},
  904. {Nano, Micro, 1},
  905. {Nano, Milli, 1},
  906. {Nano, 0, 1},
  907. {Micro, Nano, 1000},
  908. {Micro, Micro, 1},
  909. {Micro, Milli, 1},
  910. {Micro, 0, 1},
  911. {Milli, Nano, 1000 * 1000},
  912. {Milli, Micro, 1000},
  913. {Milli, Milli, 1},
  914. {Milli, 0, 1},
  915. {0, Nano, 1000 * 1000 * 1000},
  916. {0, Micro, 1000 * 1000},
  917. {0, Milli, 1000},
  918. {0, 0, 1},
  919. }
  920. for _, item := range table {
  921. q := NewScaledQuantity(1, item.fromScale)
  922. if e, a := item.expected, q.ScaledValue(item.toScale); e != a {
  923. t.Errorf("%v to %v: Expected %v, got %v", item.fromScale, item.toScale, e, a)
  924. }
  925. }
  926. }
  927. func TestUninitializedNoCrash(t *testing.T) {
  928. var q Quantity
  929. q.Value()
  930. q.MilliValue()
  931. q.Copy()
  932. _ = q.String()
  933. q.MarshalJSON()
  934. }
  935. func TestCopy(t *testing.T) {
  936. q := NewQuantity(5, DecimalSI)
  937. c := q.Copy()
  938. c.Set(6)
  939. if q.Value() == 6 {
  940. t.Errorf("Copy didn't")
  941. }
  942. }
  943. func TestQFlagSet(t *testing.T) {
  944. qf := qFlag{&Quantity{}}
  945. qf.Set("1Ki")
  946. if e, a := "1Ki", qf.String(); e != a {
  947. t.Errorf("Unexpected result %v != %v", e, a)
  948. }
  949. }
  950. func TestQFlagIsPFlag(t *testing.T) {
  951. var pfv pflag.Value = qFlag{}
  952. if e, a := "quantity", pfv.Type(); e != a {
  953. t.Errorf("Unexpected result %v != %v", e, a)
  954. }
  955. }
  956. func TestSub(t *testing.T) {
  957. tests := []struct {
  958. a Quantity
  959. b Quantity
  960. expected Quantity
  961. }{
  962. {decQuantity(10, 0, DecimalSI), decQuantity(1, 1, DecimalSI), decQuantity(0, 0, DecimalSI)},
  963. {decQuantity(10, 0, DecimalSI), decQuantity(1, 0, BinarySI), decQuantity(9, 0, DecimalSI)},
  964. {decQuantity(10, 0, BinarySI), decQuantity(1, 0, DecimalSI), decQuantity(9, 0, BinarySI)},
  965. {Quantity{Format: DecimalSI}, decQuantity(50, 0, DecimalSI), decQuantity(-50, 0, DecimalSI)},
  966. {decQuantity(50, 0, DecimalSI), Quantity{Format: DecimalSI}, decQuantity(50, 0, DecimalSI)},
  967. {Quantity{Format: DecimalSI}, Quantity{Format: DecimalSI}, decQuantity(0, 0, DecimalSI)},
  968. }
  969. for i, test := range tests {
  970. test.a.Sub(test.b)
  971. if test.a.Cmp(test.expected) != 0 {
  972. t.Errorf("[%d] Expected %q, got %q", i, test.expected.String(), test.a.String())
  973. }
  974. }
  975. }
  976. func TestNeg(t *testing.T) {
  977. tests := []struct {
  978. a Quantity
  979. b Quantity
  980. expected Quantity
  981. }{
  982. {a: intQuantity(0, 0, DecimalSI), expected: intQuantity(0, 0, DecimalSI)},
  983. {a: Quantity{}, expected: Quantity{}},
  984. {a: intQuantity(10, 0, BinarySI), expected: intQuantity(-10, 0, BinarySI)},
  985. {a: intQuantity(-10, 0, BinarySI), expected: intQuantity(10, 0, BinarySI)},
  986. {a: decQuantity(0, 0, DecimalSI), expected: intQuantity(0, 0, DecimalSI)},
  987. {a: decQuantity(10, 0, BinarySI), expected: intQuantity(-10, 0, BinarySI)},
  988. {a: decQuantity(-10, 0, BinarySI), expected: intQuantity(10, 0, BinarySI)},
  989. }
  990. for i, test := range tests {
  991. a := test.a.Copy()
  992. a.Neg()
  993. // ensure value is same
  994. if a.Cmp(test.expected) != 0 {
  995. t.Errorf("[%d] Expected %q, got %q", i, test.expected.String(), a.String())
  996. }
  997. }
  998. }
  999. func TestAdd(t *testing.T) {
  1000. tests := []struct {
  1001. a Quantity
  1002. b Quantity
  1003. expected Quantity
  1004. }{
  1005. {decQuantity(10, 0, DecimalSI), decQuantity(1, 1, DecimalSI), decQuantity(20, 0, DecimalSI)},
  1006. {decQuantity(10, 0, DecimalSI), decQuantity(1, 0, BinarySI), decQuantity(11, 0, DecimalSI)},
  1007. {decQuantity(10, 0, BinarySI), decQuantity(1, 0, DecimalSI), decQuantity(11, 0, BinarySI)},
  1008. {Quantity{Format: DecimalSI}, decQuantity(50, 0, DecimalSI), decQuantity(50, 0, DecimalSI)},
  1009. {decQuantity(50, 0, DecimalSI), Quantity{Format: DecimalSI}, decQuantity(50, 0, DecimalSI)},
  1010. {Quantity{Format: DecimalSI}, Quantity{Format: DecimalSI}, decQuantity(0, 0, DecimalSI)},
  1011. }
  1012. for i, test := range tests {
  1013. test.a.Add(test.b)
  1014. if test.a.Cmp(test.expected) != 0 {
  1015. t.Errorf("[%d] Expected %q, got %q", i, test.expected.String(), test.a.String())
  1016. }
  1017. }
  1018. }
  1019. func TestAddSubRoundTrip(t *testing.T) {
  1020. for k := -10; k <= 10; k++ {
  1021. q := Quantity{Format: DecimalSI}
  1022. var order []int64
  1023. for i := 0; i < 100; i++ {
  1024. j := rand.Int63()
  1025. order = append(order, j)
  1026. q.Add(*NewScaledQuantity(j, Scale(k)))
  1027. }
  1028. for _, j := range order {
  1029. q.Sub(*NewScaledQuantity(j, Scale(k)))
  1030. }
  1031. if !q.IsZero() {
  1032. t.Errorf("addition and subtraction did not cancel: %s", &q)
  1033. }
  1034. }
  1035. }
  1036. func TestAddSubRoundTripAcrossScales(t *testing.T) {
  1037. q := Quantity{Format: DecimalSI}
  1038. var order []int64
  1039. for i := 0; i < 100; i++ {
  1040. j := rand.Int63()
  1041. order = append(order, j)
  1042. q.Add(*NewScaledQuantity(j, Scale(j%20-10)))
  1043. }
  1044. for _, j := range order {
  1045. q.Sub(*NewScaledQuantity(j, Scale(j%20-10)))
  1046. }
  1047. if !q.IsZero() {
  1048. t.Errorf("addition and subtraction did not cancel: %s", &q)
  1049. }
  1050. }
  1051. func TestNegateRoundTrip(t *testing.T) {
  1052. for _, asDec := range []bool{false, true} {
  1053. for k := -10; k <= 10; k++ {
  1054. for i := 0; i < 100; i++ {
  1055. j := rand.Int63()
  1056. q := *NewScaledQuantity(j, Scale(k))
  1057. if asDec {
  1058. q.AsDec()
  1059. }
  1060. b := q.Copy()
  1061. b.Neg()
  1062. b.Neg()
  1063. if b.Cmp(q) != 0 {
  1064. t.Errorf("double negation did not cancel: %s", &q)
  1065. }
  1066. }
  1067. }
  1068. }
  1069. }
  1070. func benchmarkQuantities() []Quantity {
  1071. return []Quantity{
  1072. intQuantity(1024*1024*1024, 0, BinarySI),
  1073. intQuantity(1024*1024*1024*1024, 0, BinarySI),
  1074. intQuantity(1000000, 3, DecimalSI),
  1075. intQuantity(1000000000, 0, DecimalSI),
  1076. intQuantity(1, -3, DecimalSI),
  1077. intQuantity(80, -3, DecimalSI),
  1078. intQuantity(1080, -3, DecimalSI),
  1079. intQuantity(0, 0, BinarySI),
  1080. intQuantity(1, 9, DecimalExponent),
  1081. intQuantity(1, -9, DecimalSI),
  1082. intQuantity(1000000, 10, DecimalSI),
  1083. }
  1084. }
  1085. func BenchmarkQuantityString(b *testing.B) {
  1086. values := benchmarkQuantities()
  1087. b.ResetTimer()
  1088. var s string
  1089. for i := 0; i < b.N; i++ {
  1090. q := values[i%len(values)]
  1091. q.s = ""
  1092. s = q.String()
  1093. }
  1094. b.StopTimer()
  1095. if len(s) == 0 {
  1096. b.Fatal(s)
  1097. }
  1098. }
  1099. func BenchmarkQuantityStringPrecalc(b *testing.B) {
  1100. values := benchmarkQuantities()
  1101. for i := range values {
  1102. _ = values[i].String()
  1103. }
  1104. b.ResetTimer()
  1105. var s string
  1106. for i := 0; i < b.N; i++ {
  1107. q := values[i%len(values)]
  1108. s = q.String()
  1109. }
  1110. b.StopTimer()
  1111. if len(s) == 0 {
  1112. b.Fatal(s)
  1113. }
  1114. }
  1115. func BenchmarkQuantityStringBinarySI(b *testing.B) {
  1116. values := benchmarkQuantities()
  1117. for i := range values {
  1118. values[i].Format = BinarySI
  1119. }
  1120. b.ResetTimer()
  1121. var s string
  1122. for i := 0; i < b.N; i++ {
  1123. q := values[i%len(values)]
  1124. q.s = ""
  1125. s = q.String()
  1126. }
  1127. b.StopTimer()
  1128. if len(s) == 0 {
  1129. b.Fatal(s)
  1130. }
  1131. }
  1132. func BenchmarkQuantityMarshalJSON(b *testing.B) {
  1133. values := benchmarkQuantities()
  1134. b.ResetTimer()
  1135. for i := 0; i < b.N; i++ {
  1136. q := values[i%len(values)]
  1137. q.s = ""
  1138. if _, err := q.MarshalJSON(); err != nil {
  1139. b.Fatal(err)
  1140. }
  1141. }
  1142. b.StopTimer()
  1143. }
  1144. func BenchmarkQuantityUnmarshalJSON(b *testing.B) {
  1145. values := benchmarkQuantities()
  1146. var json [][]byte
  1147. for _, v := range values {
  1148. data, _ := v.MarshalJSON()
  1149. json = append(json, data)
  1150. }
  1151. b.ResetTimer()
  1152. for i := 0; i < b.N; i++ {
  1153. var q Quantity
  1154. if err := q.UnmarshalJSON(json[i%len(values)]); err != nil {
  1155. b.Fatal(err)
  1156. }
  1157. }
  1158. b.StopTimer()
  1159. }
  1160. func BenchmarkParseQuantity(b *testing.B) {
  1161. values := benchmarkQuantities()
  1162. var strings []string
  1163. for _, v := range values {
  1164. strings = append(strings, v.String())
  1165. }
  1166. b.ResetTimer()
  1167. for i := 0; i < b.N; i++ {
  1168. if _, err := ParseQuantity(strings[i%len(values)]); err != nil {
  1169. b.Fatal(err)
  1170. }
  1171. }
  1172. b.StopTimer()
  1173. }
  1174. func BenchmarkCanonicalize(b *testing.B) {
  1175. values := benchmarkQuantities()
  1176. b.ResetTimer()
  1177. buffer := make([]byte, 0, 100)
  1178. for i := 0; i < b.N; i++ {
  1179. s, _ := values[i%len(values)].CanonicalizeBytes(buffer)
  1180. if len(s) == 0 {
  1181. b.Fatal(s)
  1182. }
  1183. }
  1184. b.StopTimer()
  1185. }
  1186. func BenchmarkQuantityRoundUp(b *testing.B) {
  1187. values := benchmarkQuantities()
  1188. b.ResetTimer()
  1189. for i := 0; i < b.N; i++ {
  1190. q := values[i%len(values)]
  1191. copied := q
  1192. copied.RoundUp(-3)
  1193. }
  1194. b.StopTimer()
  1195. }
  1196. func BenchmarkQuantityCopy(b *testing.B) {
  1197. values := benchmarkQuantities()
  1198. b.ResetTimer()
  1199. for i := 0; i < b.N; i++ {
  1200. values[i%len(values)].Copy()
  1201. }
  1202. b.StopTimer()
  1203. }
  1204. func BenchmarkQuantityAdd(b *testing.B) {
  1205. values := benchmarkQuantities()
  1206. base := &Quantity{}
  1207. b.ResetTimer()
  1208. for i := 0; i < b.N; i++ {
  1209. q := values[i%len(values)]
  1210. base.d.Dec = nil
  1211. base.i = int64Amount{value: 100}
  1212. base.Add(q)
  1213. }
  1214. b.StopTimer()
  1215. }
  1216. func BenchmarkQuantityCmp(b *testing.B) {
  1217. values := benchmarkQuantities()
  1218. b.ResetTimer()
  1219. for i := 0; i < b.N; i++ {
  1220. q := values[i%len(values)]
  1221. if q.Cmp(q) != 0 {
  1222. b.Fatal(q)
  1223. }
  1224. }
  1225. b.StopTimer()
  1226. }