func TestDecGobEncoding(t *testing.T) { var medium bytes.Buffer enc := gob.NewEncoder(&medium) dec := gob.NewDecoder(&medium) for i, test := range decGobEncodingTests { for j := 0; j < 2; j++ { for k := inf.Scale(-5); k <= 5; k++ { medium.Reset() // empty buffer for each test case (in case of failures) stest := test if j != 0 { // negative numbers stest = "-" + test } var tx inf.Dec tx.SetString(stest) tx.SetScale(k) // test with positive, negative, and zero scale if err := enc.Encode(&tx); err != nil { t.Errorf("#%d%c: encoding failed: %s", i, 'a'+j, err) } var rx inf.Dec if err := dec.Decode(&rx); err != nil { t.Errorf("#%d%c: decoding failed: %s", i, 'a'+j, err) } if rx.Cmp(&tx) != 0 { t.Errorf("#%d%c: transmission failed: got %s want %s", i, 'a'+j, &rx, &tx) } } } } }
// ParseQuantity turns str into a Quantity, or returns an error. func ParseQuantity(str string) (*Quantity, error) { parts := splitRE.FindStringSubmatch(strings.TrimSpace(str)) // regexp returns are entire match, followed by an entry for each () section. if len(parts) != 3 { return nil, ErrFormatWrong } amount := new(inf.Dec) if _, ok := amount.SetString(parts[1]); !ok { return nil, ErrNumeric } base, exponent, format, ok := quantitySuffixer.interpret(suffix(parts[2])) if !ok { return nil, ErrSuffix } // So that no one but us has to think about suffixes, remove it. if base == 10 { amount.SetScale(amount.Scale() + inf.Scale(-exponent)) } else if base == 2 { // numericSuffix = 2 ** exponent numericSuffix := big.NewInt(1).Lsh(bigOne, uint(exponent)) ub := amount.UnscaledBig() amount.SetUnscaledBig(ub.Mul(ub, numericSuffix)) } // Cap at min/max bounds. sign := amount.Sign() if sign == -1 { amount.Neg(amount) } // This rounds non-zero values up to the minimum representable // value, under the theory that if you want some resources, you // should get some resources, even if you asked for way too small // of an amount. // Arguably, this should be inf.RoundHalfUp (normal rounding), but // that would have the side effect of rounding values < .5m to zero. if v, ok := amount.Unscaled(); v != int64(0) || !ok { amount.Round(amount, 3, inf.RoundUp) } // The max is just a simple cap. if amount.Cmp(maxAllowed) > 0 { amount.Set(maxAllowed) } if format == BinarySI && amount.Cmp(decOne) < 0 && amount.Cmp(decZero) > 0 { // This avoids rounding and hopefully confusion, too. format = DecimalSI } if sign == -1 { amount.Neg(amount) } return &Quantity{amount, format}, nil }
func TestDecSetString(t *testing.T) { tmp := new(inf.Dec) for i, test := range decStringTests { if test.scale < 0 { // SetString only supports scale >= 0 continue } // initialize to a non-zero value so that issues with parsing // 0 are detected tmp.Set(inf.NewDec(1234567890, 123)) n1, ok1 := new(inf.Dec).SetString(test.in) n2, ok2 := tmp.SetString(test.in) expected := inf.NewDec(test.val, test.scale) if ok1 != test.ok || ok2 != test.ok { t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok) continue } if !ok1 { if n1 != nil { t.Errorf("#%d (input '%s') n1 != nil", i, test.in) } continue } if !ok2 { if n2 != nil { t.Errorf("#%d (input '%s') n2 != nil", i, test.in) } continue } if n1.Cmp(expected) != 0 { t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val) } if n2.Cmp(expected) != 0 { t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val) } } }
func TestLowLevelAPIOnly(t *testing.T) { type CDR struct { Imsi string Timestamp time.Time Duration int64 Carrier string Cost *inf.Dec } strat := func(c gocql.ColumnInfo) (reflect.StructField, bool) { st := reflect.TypeOf((*CDR)(nil)).Elem() switch c.Name { case "imsi": return st.FieldByName("Imsi") case "timestamp": return st.FieldByName("Timestamp") case "duration": return st.FieldByName("Duration") case "carrier": return st.FieldByName("Carrier") case "charge": return st.FieldByName("Cost") default: return reflect.StructField{}, false } } s := setup(t, "calls") measurements := 43 start := time.Now() for i := 0; i < measurements; i++ { cost := new(inf.Dec) cost.SetString(fmt.Sprintf("1.0%d", i)) cdr := CDR{ Imsi: "240080852000132", Timestamp: start.Add(time.Duration(i) * time.Millisecond), Duration: int64(i) + 60, Carrier: "TMOB", Cost: cost, } if err := Bind(`INSERT INTO calls (imsi, timestamp, duration, carrier, charge) VALUES (?, ?, ?, ?, ?)`, cdr).Use(strat).Exec(s); err != nil { t.Fatal(err) } } q := s.Query(`SELECT imsi, timestamp, duration, carrier, charge FROM calls`) b := BindQuery(q).Use(strat) count := 0 var r CDR for b.Scan(&r) { count++ assert.Equal(t, "TMOB", r.Carrier) } err := b.Close() assert.Nil(t, err, "Could not close binding") assert.Equal(t, measurements, count) }
func ExampleDec_SetString() { d := new(inf.Dec) d.SetString("012345.67890") // decimal; leading 0 ignored; trailing 0 kept fmt.Println(d) // Output: 12345.67890 }