New Upstream Release - golang-github-linkedin-goavro
Ready changes
Summary
Merged new upstream version: 2.11.1 (was: 2.10.1).
Resulting package
Built on 2022-05-28T04:24 (took 8m52s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-releases golang-github-linkedin-goavro-dev
Lintian Result
Diff
diff --git a/canonical.go b/canonical.go
index fe69f45..32ac608 100644
--- a/canonical.go
+++ b/canonical.go
@@ -84,7 +84,7 @@ func pcfObject(jsonMap map[string]interface{}, parentNamespace string, typeLooku
}
parentNamespace = namespace
}
- } else if objectType, ok := jsonMap["type"]; ok && objectType == "record" {
+ } else if objectType, ok := jsonMap["type"]; ok && (objectType == "record" || objectType == "enum" || objectType == "fixed") {
namespace = parentNamespace
}
diff --git a/canonical_test.go b/canonical_test.go
index dd43dba..811e0eb 100644
--- a/canonical_test.go
+++ b/canonical_test.go
@@ -154,6 +154,18 @@ func TestCanonicalSchema(t *testing.T) {
Schema: `{"namespace":"x.y.z", "type":"enum", "name":"foo", "doc":"foo bar", "symbols":["A1", "A2"]}`,
Canonical: `{"name":"x.y.z.foo","type":"enum","symbols":["A1","A2"]}`,
},
+ {
+ Schema: `{"type":"record", "name":"a.b.foo", "namespace":"x.y", "fields":[{"name":"bar","type":"enum","symbols":["A1","A2"]}]}`,
+ Canonical: `{"name":"a.b.foo","type":"record","fields":[{"name":"x.y.bar","type":"enum","symbols":["A1","A2"]}]}`,
+ },
+ {
+ Schema: `{"type":"record", "name":"foo", "namespace":"x.y", "fields":[{"name":"bar","type":"enum","symbols":["A1","A2"]}]}`,
+ Canonical: `{"name":"x.y.foo","type":"record","fields":[{"name":"x.y.bar","type":"enum","symbols":["A1","A2"]}]}`,
+ },
+ {
+ Schema: `{"type":"record", "name":"foo", "namespace":"x.y", "fields":[{"name":"a.b.bar","type":"enum","symbols":["A1","A2"]}]}`,
+ Canonical: `{"name":"x.y.foo","type":"record","fields":[{"name":"a.b.bar","type":"enum","symbols":["A1","A2"]}]}`,
+ },
{
Schema: `{"name":"foo","type":"fixed","size":15}`,
Canonical: `{"name":"foo","type":"fixed","size":15}`,
@@ -162,6 +174,14 @@ func TestCanonicalSchema(t *testing.T) {
Schema: `{"namespace":"x.y.z", "type":"fixed", "name":"foo", "doc":"foo bar", "size":32}`,
Canonical: `{"name":"x.y.z.foo","type":"fixed","size":32}`,
},
+ {
+ Schema: `{"type":"record", "name":"foo", "namespace":"x.y", "fields":[{"name":"bar","type":"fixed", "doc":"foo bar", "size":32}]}`,
+ Canonical: `{"name":"x.y.foo","type":"record","fields":[{"name":"x.y.bar","type":"fixed","size":32}]}`,
+ },
+ {
+ Schema: `{"type":"record", "name":"foo", "namespace":"x.y", "fields":[{"name":"a.b.bar","type":"fixed", "doc":"foo bar", "size":32}]}`,
+ Canonical: `{"name":"x.y.foo","type":"record","fields":[{"name":"a.b.bar","type":"fixed","size":32}]}`,
+ },
{
Schema: `{ "items":{"type":"null"}, "type":"array"}`,
Canonical: `{"type":"array","items":"null"}`,
diff --git a/codec.go b/codec.go
index 9e3aac4..ac05b10 100644
--- a/codec.go
+++ b/codec.go
@@ -566,11 +566,26 @@ func buildCodecForTypeDescribedByString(st map[string]*Codec, enclosingNamespace
isLogicalType = true
searchType = fmt.Sprintf("%s.%s", typeName, lt)
}
+
// NOTE: When codec already exists, return it. This includes both primitive and
// logicalType codecs added in NewCodec, and user-defined types, added while
// building the codec.
if cd, ok := st[searchType]; ok {
- return cd, nil
+
+ // For "bytes.decimal" types verify that the scale and precision in this schema map match a cached codec before
+ // using the cached codec in favor of creating a new codec.
+ if searchType == "bytes.decimal" {
+
+ // Search the cached codecs for a "bytes.decimal" codec with a "precision" and "scale" specified in the key,
+ // only if that matches return the cached codec. Otherwise, create a new codec for this "bytes.decimal".
+ decimalSearchType := fmt.Sprintf("bytes.decimal.%d.%d", int(schemaMap["precision"].(float64)), int(schemaMap["scale"].(float64)))
+ if cd2, ok := st[decimalSearchType]; ok {
+ return cd2, nil
+ }
+
+ } else {
+ return cd, nil
+ }
}
// Avro specification allows abbreviation of type name inside a namespace.
@@ -596,6 +611,8 @@ func buildCodecForTypeDescribedByString(st map[string]*Codec, enclosingNamespace
return makeDecimalBytesCodec(st, enclosingNamespace, schemaMap)
case "fixed.decimal":
return makeDecimalFixedCodec(st, enclosingNamespace, schemaMap)
+ case "string.validated-string":
+ return makeValidatedStringCodec(st, enclosingNamespace, schemaMap)
default:
if isLogicalType {
delete(schemaMap, "logicalType")
diff --git a/codec_test.go b/codec_test.go
index 268d431..b4729e5 100644
--- a/codec_test.go
+++ b/codec_test.go
@@ -300,3 +300,34 @@ func ExampleSingleItemDecoding() {
fmt.Println(datum)
// Output: 3
}
+
+func Test_buildCodecForTypeDescribedByString_CacheRespectsPrecisionScale(t *testing.T) {
+ schemaMap := map[string]interface{}{
+ "type": "bytes",
+ "logicalType": "decimal",
+ "precision": float64(4),
+ "scale": float64(2),
+ }
+ cachedCodecIdentifier := "preexisting-cached-coded"
+ cache := map[string]*Codec{
+ "bytes.decimal": nil, // precision.scale-agnostic codec
+ "bytes.decimal.4.2": {
+ schemaOriginal: cachedCodecIdentifier, // using field as identifier
+ },
+ }
+
+ // cached bytes.decimal codec with matching precision.scale is returned
+ cacheHit, err := buildCodecForTypeDescribedByString(cache, "", "bytes", schemaMap, nil)
+ ensureError(t, err) // ensure NO error
+ if cacheHit.schemaOriginal != cachedCodecIdentifier {
+ t.Errorf("GOT: %v; WANT: %v", cacheHit.schemaOriginal, cachedCodecIdentifier)
+ }
+
+ // cached codec with unmatching precision.scale is not returned
+ schemaMap["scale"] = float64(1)
+ cacheMiss, err := buildCodecForTypeDescribedByString(cache, "", "bytes", schemaMap, nil)
+ ensureError(t, err) // ensure NO error
+ if cacheMiss.schemaOriginal == cachedCodecIdentifier {
+ t.Errorf("GOT: %v; WANT: %v", cacheMiss.schemaOriginal, "!= "+cachedCodecIdentifier)
+ }
+}
diff --git a/debian/changelog b/debian/changelog
index 12a2ef1..420f8b7 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-github-linkedin-goavro (2.11.1-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk> Sat, 28 May 2022 04:15:40 -0000
+
golang-github-linkedin-goavro (2.10.1-1) unstable; urgency=medium
* Team upload.
diff --git a/debian/patches/01-fix-tests-32bit-arch.patch b/debian/patches/01-fix-tests-32bit-arch.patch
index 3f2c3ef..d13af8e 100644
--- a/debian/patches/01-fix-tests-32bit-arch.patch
+++ b/debian/patches/01-fix-tests-32bit-arch.patch
@@ -1,6 +1,8 @@
---- a/union_test.go
-+++ b/union_test.go
-@@ -307,8 +307,8 @@
+Index: golang-github-linkedin-goavro/union_test.go
+===================================================================
+--- golang-github-linkedin-goavro.orig/union_test.go
++++ golang-github-linkedin-goavro/union_test.go
+@@ -307,8 +307,8 @@ func TestUnionJSON(t *testing.T) {
testJSONDecodePass(t, `["null","int"]`, nil, []byte("null"))
testJSONDecodePass(t, `["null","int","long"]`, Union("int", 3), []byte(`3`))
testJSONDecodePass(t, `["null","long","int"]`, Union("int", 3), []byte(`3`))
@@ -11,9 +13,11 @@
testJSONDecodePass(t, `["null","float","int","long"]`, Union("float", 6.77), []byte(`6.77`))
testJSONDecodePass(t, `["null","int","float","long"]`, Union("float", 6.77), []byte(`6.77`))
testJSONDecodePass(t, `["null","double","int","long"]`, Union("double", 6.77), []byte(`6.77`))
---- a/integer_test.go
-+++ b/integer_test.go
-@@ -21,14 +21,14 @@
+Index: golang-github-linkedin-goavro/integer_test.go
+===================================================================
+--- golang-github-linkedin-goavro.orig/integer_test.go
++++ golang-github-linkedin-goavro/integer_test.go
+@@ -21,14 +21,14 @@ func TestPrimitiveIntBinary(t *testing.T
testBinaryEncodeFailBadDatumType(t, `"int"`, "some string")
testBinaryDecodeFailShortBuffer(t, `"int"`, []byte{0xfd, 0xff, 0xff, 0xff})
testBinaryCodecPass(t, `"int"`, -1, []byte{0x01})
diff --git a/examples/165/main.go b/examples/165/main.go
index b1cf4ce..687740c 100644
--- a/examples/165/main.go
+++ b/examples/165/main.go
@@ -37,7 +37,7 @@ package main
import (
"os"
- "github.com/linkedin/goavro"
+ "github.com/linkedin/goavro/v2"
)
const loginEventAvroSchema = `{"type": "record", "name": "LoginEvent", "fields": [{"name": "Username", "type": "string"}]}`
diff --git a/examples/soe/main.go b/examples/soe/main.go
index a615024..21c76ce 100644
--- a/examples/soe/main.go
+++ b/examples/soe/main.go
@@ -3,7 +3,7 @@ package main
import (
"fmt"
- "github.com/linkedin/goavro"
+ "github.com/linkedin/goavro/v2"
)
func main() {
diff --git a/logical_type.go b/logical_type.go
index 94ce35a..700980f 100644
--- a/logical_type.go
+++ b/logical_type.go
@@ -13,12 +13,16 @@ import (
"errors"
"fmt"
"math/big"
+ "regexp"
+ "strings"
"time"
)
type toNativeFn func([]byte) (interface{}, []byte, error)
type fromNativeFn func([]byte, interface{}) ([]byte, error)
+var reFromPattern = make(map[string]*regexp.Regexp)
+
//////////////////////////////////////////////////////////////////////////////////////////////
// date logical type - to/from time.Time, time.UTC location
//////////////////////////////////////////////////////////////////////////////////////////////
@@ -123,7 +127,7 @@ func timeMicrosFromNative(fn fromNativeFn) fromNativeFn {
return fn(b, val)
case time.Duration:
- duration := int32(val.Nanoseconds() / int64(time.Microsecond))
+ duration := val.Nanoseconds() / int64(time.Microsecond)
return fn(b, duration)
default:
@@ -233,14 +237,14 @@ func precisionAndScaleFromSchemaMap(schemaMap map[string]interface{}) (int, int,
return 0, 0, fmt.Errorf("cannot create decimal logical type with wrong precision type; expected: float64; received: %T", p1)
}
p3 := int(p2)
- if p3 <= 1 {
+ if p3 < 1 {
return 0, 0, fmt.Errorf("cannot create decimal logical type when precision is less than one: %d", p3)
}
var s3 int // scale defaults to 0 if not set
if s1, ok := schemaMap["scale"]; ok {
s2, ok := s1.(float64)
if !ok {
- return 0, 0, fmt.Errorf("cannot create decimal logical type with wrong precision type; expected: float64; received: %T", p1)
+ return 0, 0, fmt.Errorf("cannot create decimal logical type with wrong scale type; expected: float64; received: %T", s1)
}
s3 = int(s2)
if s3 < 0 {
@@ -267,6 +271,11 @@ func makeDecimalBytesCodec(st map[string]*Codec, enclosingNamespace string, sche
if err != nil {
return nil, fmt.Errorf("Bytes ought to have valid name: %s", err)
}
+
+ // Add an additional cached codec for this "bytes.decimal" keyed also by "precision" and "scale"
+ decimalSearchType := fmt.Sprintf("bytes.decimal.%d.%d", precision, scale)
+ st[decimalSearchType] = c
+
c.binaryFromNative = decimalBytesFromNative(bytesBinaryFromNative, toSignedBytes, precision, scale)
c.textualFromNative = decimalBytesFromNative(bytesTextualFromNative, toSignedBytes, precision, scale)
c.nativeFromBinary = nativeFromDecimalBytes(bytesNativeFromBinary, precision, scale)
@@ -335,6 +344,85 @@ func makeDecimalFixedCodec(st map[string]*Codec, enclosingNamespace string, sche
return c, nil
}
+func makeValidatedStringCodec(st map[string]*Codec, enclosingNamespace string, schemaMap map[string]interface{}) (*Codec, error) {
+ pattern, ok := schemaMap["pattern"]
+ if !ok {
+ return nil, errors.New("cannot create validated-string logical type without pattern")
+ }
+
+ patternStr := strings.TrimSpace(pattern.(string))
+ if reFromPattern[patternStr] == nil {
+ var (
+ regexpr *regexp.Regexp
+ err error
+ )
+ if regexpr, err = regexp.Compile(patternStr); err != nil {
+ return nil, err
+ }
+
+ reFromPattern[patternStr] = regexpr
+ }
+
+ if _, ok := schemaMap["name"]; !ok {
+ schemaMap["name"] = "string.validated-string"
+ }
+
+ c, err := registerNewCodec(st, schemaMap, enclosingNamespace)
+ if err != nil {
+ return nil, err
+ }
+
+ c.binaryFromNative = validatedStringBinaryFromNative(c.binaryFromNative)
+ c.textualFromNative = validatedStringTextualFromNative(c.textualFromNative)
+ c.nativeFromBinary = validatedStringNativeFromBinary(c.nativeFromBinary, patternStr)
+ c.nativeFromTextual = validatedStringNativeFromTextual(c.nativeFromTextual, patternStr)
+ return c, nil
+}
+
+func validatedStringBinaryFromNative(fromNativeFn fromNativeFn) fromNativeFn {
+ return func(b []byte, d interface{}) ([]byte, error) {
+ return stringBinaryFromNative(b, d)
+ }
+}
+
+func validatedStringTextualFromNative(fromNativeFn fromNativeFn) fromNativeFn {
+ return func(b []byte, d interface{}) ([]byte, error) {
+ return stringTextualFromNative(b, d)
+ }
+}
+
+func validatedStringNativeFromBinary(fn toNativeFn, pattern string) toNativeFn {
+ return func(bytes []byte) (interface{}, []byte, error) {
+ fn, newBytes, err := stringNativeFromBinary(bytes)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ result := fn.(string)
+ if ok := reFromPattern[pattern].MatchString(result); !ok {
+ return nil, bytes, fmt.Errorf("cannot match input string against validation pattern: %q does not match %q", result, pattern)
+ }
+
+ return fn, newBytes, nil
+ }
+}
+
+func validatedStringNativeFromTextual(fn toNativeFn, pattern string) toNativeFn {
+ return func(bytes []byte) (interface{}, []byte, error) {
+ fn, newBytes, err := stringNativeFromTextual(bytes)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ result := fn.(string)
+ if ok := reFromPattern[pattern].MatchString(result); !ok {
+ return nil, bytes, fmt.Errorf("cannot match input string against validation pattern: %q does not match %q", result, pattern)
+ }
+
+ return fn, newBytes, nil
+ }
+}
+
func padBytes(bytes []byte, fixedSize uint) []byte {
s := int(fixedSize)
padded := make([]byte, s, s)
diff --git a/logical_type_test.go b/logical_type_test.go
index d3e2bec..20f7903 100644
--- a/logical_type_test.go
+++ b/logical_type_test.go
@@ -11,11 +11,17 @@ package goavro
import (
"fmt"
+ "math"
"math/big"
"testing"
"time"
)
+const (
+ precision = "precision"
+ scale = "scale"
+)
+
func TestSchemaLogicalType(t *testing.T) {
testSchemaValid(t, `{"type": "long", "logicalType": "timestamp-millis"}`)
testSchemaInvalid(t, `{"type": "bytes", "logicalType": "decimal"}`, "precision")
@@ -37,8 +43,7 @@ func TestLongLogicalTypeFallback(t *testing.T) {
func TestTimeStampMillisLogicalTypeEncode(t *testing.T) {
schema := `{"type": "long", "logicalType": "timestamp-millis"}`
testBinaryDecodeFail(t, schema, []byte(""), "short buffer")
- t.Skip("this test is broken")
- testBinaryEncodeFail(t, schema, "test", "cannot transform binary timestamp-millis, expected time.Time")
+ testBinaryEncodeFail(t, schema, "test", "cannot transform to binary timestamp-millis, expected time.Time or Go numeric")
testBinaryCodecPass(t, schema, time.Date(2006, 1, 2, 15, 04, 05, 565000000, time.UTC), []byte("\xfa\x82\xac\xba\x91\x42"))
}
@@ -51,8 +56,7 @@ func TestTimeStampMillisLogicalTypeUnionEncode(t *testing.T) {
func TestTimeStampMicrosLogicalTypeEncode(t *testing.T) {
schema := `{"type": "long", "logicalType": "timestamp-micros"}`
testBinaryDecodeFail(t, schema, []byte(""), "short buffer")
- t.Skip("this test is broken")
- testBinaryEncodeFail(t, schema, "test", "cannot transform binary timestamp-micros, expected time.Time")
+ testBinaryEncodeFail(t, schema, "test", "cannot transform to binary timestamp-micros, expected time.Time or Go numeric")
testBinaryCodecPass(t, schema, time.Date(2006, 1, 2, 15, 04, 05, 565283000, time.UTC), []byte("\xc6\x8d\xf7\xe7\xaf\xd8\x84\x04"))
}
@@ -79,21 +83,18 @@ func TestTimeMicrosLogicalTypeEncode(t *testing.T) {
schema := `{"type": "long", "logicalType": "time-micros"}`
testBinaryDecodeFail(t, schema, []byte(""), "short buffer")
testBinaryEncodeFail(t, schema, "test", "cannot transform to binary time-micros, expected time.Duration")
- t.Skip("this test is broken")
testBinaryCodecPass(t, schema, 66904022566*time.Microsecond, []byte("\xcc\xf8\xd2\xbc\xf2\x03"))
}
func TestTimeMicrosLogicalTypeUnionEncode(t *testing.T) {
schema := `{"type": ["null", {"type": "long", "logicalType": "time-micros"}]}`
testBinaryEncodeFail(t, schema, Union("string", "test"), "cannot encode binary union: no member schema types support datum: allowed types: [null long.time-micros]")
- t.Skip("this test is broken")
testBinaryCodecPass(t, schema, Union("long.time-micros", 66904022566*time.Microsecond), []byte("\x02\xcc\xf8\xd2\xbc\xf2\x03"))
}
func TestDateLogicalTypeEncode(t *testing.T) {
schema := `{"type": "int", "logicalType": "date"}`
testBinaryDecodeFail(t, schema, []byte(""), "short buffer")
- t.Skip("this test is broken")
- testBinaryEncodeFail(t, schema, "test", "cannot transform to binary date, expected time.Time, received string")
+ testBinaryEncodeFail(t, schema, "test", "cannot transform to binary date, expected time.Time or Go numeric, received string")
testBinaryCodecPass(t, schema, time.Date(2006, 1, 2, 0, 0, 0, 0, time.UTC), []byte("\xbc\xcd\x01"))
}
@@ -163,6 +164,12 @@ func TestDecimalFixedLogicalTypeEncode(t *testing.T) {
// Encodes to 12 due to scale: 0
testBinaryEncodePass(t, schema0scale, big.NewRat(617, 50), []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c"))
testBinaryDecodePass(t, schema0scale, big.NewRat(12, 1), []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c"))
+
+ schemaPrecision1 := `{"type": "fixed", "size": 4, "logicalType": "decimal", "precision": 1, "scale": 1}`
+ testBinaryCodecPass(t, schemaPrecision1, big.NewRat(163, 10), []byte("\x00\x00\x00\xa3"))
+ testBinaryCodecPass(t, schemaPrecision1, big.NewRat(-130, 4), []byte("\xff\xff\xfe\xbb"))
+ testBinaryCodecPass(t, schemaPrecision1, big.NewRat(25, 2), []byte("\x00\x00\x00\x7d"))
+ testBinaryEncodeFail(t, schemaPrecision1, big.NewRat(math.MaxInt32, -1), "datum size ought to equal schema size")
}
func TestDecimalBytesLogicalTypeInRecordEncode(t *testing.T) {
@@ -171,6 +178,65 @@ func TestDecimalBytesLogicalTypeInRecordEncode(t *testing.T) {
testBinaryCodecPass(t, schema, map[string]interface{}{"mydecimal": big.NewRat(617, 50)}, []byte("\x04\x04\xd2"))
}
+func TestValidatedStringLogicalTypeInRecordEncode(t *testing.T) {
+ schema := `{
+ "type": "record",
+ "name": "myrecord",
+ "fields": [
+ {
+ "name": "number",
+ "doc": "Phone number inside the national network. Length between 4-14",
+ "type": {
+ "type": "string",
+ "logicalType": "validatedString",
+ "pattern": "^[\\d]{4,14}$"
+ }
+ }
+ ]
+ }`
+
+ codec, err := NewCodec(schema)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // NOTE: May omit fields when using default value
+ textual := []byte(`{"number": "667777777"}`)
+
+ // Convert textual Avro data (in Avro JSON format) to native Go form
+ native, _, err := codec.NativeFromTextual(textual)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Convert native Go form to binary Avro data
+ binary, err := codec.BinaryFromNative(nil, native)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ testSchemaValid(t, schema)
+ testBinaryCodecPass(t, schema, map[string]interface{}{"number": "667777777"}, binary)
+
+ // Convert binary Avro data back to native Go form
+ native, _, err = codec.NativeFromBinary(binary)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Convert native Go form to textual Avro data
+ textual, err = codec.TextualFromNative(nil, native)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // NOTE: Textual encoding will show all fields, even those with values that
+ // match their default values
+ if got, want := string(textual), "{\"number\":\"667777777\"}"; got != want {
+ t.Errorf("GOT: %v; WANT: %v", got, want)
+ }
+}
+
func ExampleUnion_logicalType() {
// Supported logical types and their native go types:
// * timestamp-millis - time.Time
@@ -199,3 +265,43 @@ func ExampleUnion_logicalType() {
fmt.Printf("%#v\n", out["long.timestamp-millis"].(time.Time).String())
// Output: "2006-01-02 15:04:05 +0000 UTC"
}
+
+func TestPrecisionAndScaleFromSchemaMapValidation(t *testing.T) {
+ testCasesInvalid := []struct {
+ schemaMap map[string]interface{}
+ errMsg string
+ }{
+ {map[string]interface{}{}, "cannot create decimal logical type without precision"},
+ {map[string]interface{}{
+ precision: true,
+ }, "wrong precision type"},
+ {map[string]interface{}{
+ precision: float64(0),
+ }, "precision is less than one"},
+ {map[string]interface{}{
+ precision: float64(2),
+ scale: true,
+ }, "wrong scale type"},
+ {map[string]interface{}{
+ precision: float64(2),
+ scale: float64(-1),
+ }, "scale is less than zero"},
+ {map[string]interface{}{
+ precision: float64(2),
+ scale: float64(3),
+ }, "scale is larger than precision"},
+ }
+ for _, tc := range testCasesInvalid {
+ _, _, err := precisionAndScaleFromSchemaMap(tc.schemaMap)
+ ensureError(t, err, tc.errMsg)
+ }
+
+ // validation passes
+ p, s, err := precisionAndScaleFromSchemaMap(map[string]interface{}{
+ precision: float64(1),
+ scale: float64(1),
+ })
+ if p != 1 || s != 1 || err != nil {
+ t.Errorf("GOT: %v %v %v; WANT: 1 1 nil", p, s, err)
+ }
+}
diff --git a/ocf_writer.go b/ocf_writer.go
index 820af5c..32ec042 100644
--- a/ocf_writer.go
+++ b/ocf_writer.go
@@ -52,9 +52,9 @@ type OCFConfig struct {
// this field is ignored.
CompressionName string
- //MetaData specifies application specific meta data to be added to
- //the OCF file. When appending to an existing OCF, this field
- //is ignored
+ // MetaData specifies application specific meta data to be added to
+ // the OCF file. When appending to an existing OCF, this field
+ // is ignored.
MetaData map[string][]byte
}
Debdiff
File lists identical (after any substitutions)
No differences were encountered in the control files