├── .github └── workflows │ └── avro.yaml ├── LICENSE ├── Makefile ├── README.md ├── analyze.go ├── avroregistry ├── errors.go ├── errors_test.go ├── message.go ├── registry.go └── registry_test.go ├── avroregistrytest ├── avroregistrytest.go └── avroregistrytest_test.go ├── avrotypegen └── typeinfo.go ├── bench_test.go ├── benchschema.avsc ├── cmd ├── avrogo │ ├── avrotypemap │ │ ├── typemap.go │ │ ├── typemap_test.go │ │ ├── union.avsc │ │ └── union_gen_test.go │ ├── doccomment_test.go │ ├── externaltype.go │ ├── generate.go │ ├── generate_test.go │ ├── generatetestcode.go │ ├── internal │ │ ├── avrotestdata │ │ │ └── testdata.go │ │ ├── generated_tests │ │ │ ├── arrayDefault │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── arrayOfUnion │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── cloudEvent │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── duplicateRecord │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── enumDefault │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── fixedDefault │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── goTypeCustomName │ │ │ │ ├── other_test.go │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── goTypeExternal │ │ │ │ ├── other_test.go │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── goTypeFieldsOmitted │ │ │ │ ├── dummy.go │ │ │ │ └── roundtrip_test.go │ │ │ ├── goTypeFixed │ │ │ │ ├── dummy.go │ │ │ │ └── roundtrip_test.go │ │ │ ├── goTypeMap │ │ │ │ ├── dummy.go │ │ │ │ └── roundtrip_test.go │ │ │ ├── goTypeMultipleFields │ │ │ │ ├── dummy.go │ │ │ │ └── roundtrip_test.go │ │ │ ├── goTypePointer │ │ │ │ ├── dummy.go │ │ │ │ └── roundtrip_test.go │ │ │ ├── goTypeProtobufRecord │ │ │ │ ├── dummy.go │ │ │ │ ├── other_test.go │ │ │ │ └── roundtrip_test.go │ │ │ ├── goTypeSlice │ │ │ │ ├── dummy.go │ │ │ │ └── roundtrip_test.go │ │ │ ├── goTypeStruct │ │ │ │ ├── dummy.go │ │ │ │ └── roundtrip_test.go │ │ │ ├── invalidUUID │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── justEnum │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── largeRecord │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── linkedList │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── linkedListThenSomethingElse │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── mapDefault │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── multiSchema │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ ├── schema1.avsc │ │ │ │ ├── schema1_gen.go │ │ │ │ └── schema_gen.go │ │ │ ├── multiSchemaExternalType │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ ├── schema1.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── multiSchemaMutualRecursive │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ ├── schema1.avsc │ │ │ │ ├── schema1_gen.go │ │ │ │ └── schema_gen.go │ │ │ ├── nestedUnion │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── nestedUnionNestedArray │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── primitive │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── primitiveDefaults │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── primitiveIncompatible │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── recordDefault │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── sharedUnion │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── simpleArray │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── simpleEnum │ │ │ │ ├── other_test.go │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── simpleFixed │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── simpleInUnionOut │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── simpleMap │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── timestampMicros │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── unionInOut │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── unionInSimpleOut │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── unionIntVsLong │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── unionNullString │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── unionNullStringReverse │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ ├── unionToScalar │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ │ └── uuid │ │ │ │ ├── roundtrip_test.go │ │ │ │ ├── schema.avsc │ │ │ │ └── schema_gen.go │ │ └── testutil │ │ │ └── generatetest.go │ ├── main.go │ ├── outputpath_test.go │ ├── script_test.go │ ├── template.go │ ├── testdata │ │ ├── array.cue │ │ ├── cloudevent.cue │ │ ├── default.cue │ │ ├── enum.cue │ │ ├── fixed.cue │ │ ├── gotype.cue │ │ ├── logicaltype.cue │ │ ├── map.cue │ │ ├── multischema.cue │ │ ├── primitive.cue │ │ ├── record.cue │ │ ├── recursive.cue │ │ ├── schema │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ ├── object.avsc │ │ │ └── object.golden.go │ │ ├── script │ │ │ ├── non-existent-output-dir.txt │ │ │ └── relativedir.txt │ │ ├── testschema.cue │ │ └── union.cue │ └── verify_test.go ├── avsc2avdl │ ├── main.go │ ├── script_test.go │ └── testdata │ │ ├── enumwarning.txt │ │ ├── recordwarning.txt │ │ └── simple.txt └── go2avro │ ├── main.go │ ├── script_test.go │ └── testdata │ ├── badtype.txt │ ├── simple.txt │ └── unknowntype.txt ├── compat.go ├── compat_test.go ├── cover.sh ├── cue.mod ├── module.cue └── pkg │ └── github.com │ └── heetch │ └── cue-schema │ ├── avro │ ├── example │ │ └── schema.cue │ ├── protocol.cue │ └── schema.cue │ ├── cue.mod │ └── module.cue │ └── github │ ├── cue.mod │ └── module.cue │ ├── generate │ └── generate-workflow.cue │ └── workflow │ ├── event.cue │ ├── example │ └── go │ │ ├── .github │ │ └── workflows │ │ │ └── test.yaml │ │ ├── ci.yaml │ │ └── go.cue │ ├── go │ └── go.cue │ └── workflow.cue ├── decode.go ├── doc.go ├── encode.go ├── github-action.cue ├── github-action_tool.cue ├── go.mod ├── go.sum ├── gotype.go ├── gotype_test.go ├── internal ├── testtypes │ ├── cloudevent.avsc │ ├── cloudevent_gen.go │ ├── enum_string.go │ ├── generate.go │ ├── proto.go │ ├── prototest1.pb.go │ ├── prototest1.proto │ ├── prototool.yaml │ └── testtypes.go └── typeinfo │ ├── schema.go │ └── typeinfo.go ├── names.go ├── names_test.go ├── reader.go ├── reader_test.go ├── singledecoder.go ├── singledecoder_test.go ├── singleencoder.go ├── singleencoder_test.go ├── testschema1.avsc ├── testschema1_gen_test.go ├── testschema2.avsc ├── testschema2_gen_test.go ├── type.go └── type_test.go /.github/workflows/avro.yaml: -------------------------------------------------------------------------------- 1 | name: avro 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | paths: 9 | - '**.go' 10 | - 'go.*' 11 | - '**.cue' 12 | - Makefile 13 | pull_request: 14 | paths: 15 | - '**.go' 16 | - 'go.*' 17 | - '**.cue' 18 | - Makefile 19 | 20 | concurrency: 21 | group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }} 22 | cancel-in-progress: true 23 | 24 | env: 25 | directory: "." 26 | allow_lint_failure: "true" 27 | 28 | jobs: 29 | test: 30 | runs-on: ubuntu-22.04 31 | services: 32 | registry: 33 | image: lensesio/fast-data-dev:2.6.2-L0 34 | ports: 35 | - 8081:8081 36 | steps: 37 | - name: Checkout 38 | uses: actions/checkout@v4 39 | - name: Set up env 40 | uses: actions/setup-go@v5 41 | with: 42 | cache: true 43 | check-latest: true 44 | cache-dependency-path: ${{ env.directory }}/go.sum 45 | go-version-file: ${{ env.directory }}/go.mod 46 | - name: Install Tools 47 | shell: bash 48 | run: | 49 | go install github.com/mfridman/tparse@v0.12.1 50 | tgz=$(mktemp) 51 | ARCH="$(uname -s)_$(uname -m)" 52 | curl "https://github.com/cuelang/cue/releases/download/v0.0.15/cue_0.0.15_$ARCH.tar.gz" -L -o $tgz 53 | (cd /usr/local/bin && tar xzf $tgz cue) 54 | - name: "Lint: static" 55 | id: lint-static 56 | continue-on-error: false 57 | uses: golangci/golangci-lint-action@v6 58 | with: 59 | version: v1.64.8 60 | working-directory: ${{ env.directory }} 61 | args: --timeout=5m 62 | only-new-issues: true 63 | - name: "Lint: security" 64 | id: lint-security 65 | continue-on-error: true 66 | working-directory: ${{ env.directory }} 67 | run: | 68 | go install golang.org/x/vuln/cmd/govulncheck@latest 69 | govulncheck ./... 70 | - name: Build 71 | run: | 72 | make build 73 | - name: Unit tests 74 | working-directory: ${{ env.directory }} 75 | env: 76 | CGO_ENABLED: "1" 77 | KAFKA_REGISTRY_ADDR: 127.0.0.1:8081 78 | run: | 79 | make test 80 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Heetch 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | .PHONY: test build 3 | 4 | build: 5 | go build ./... 6 | 7 | test: 8 | go install ./cmd/... 9 | go generate . ./cmd/... 10 | go test ./... -cover -race -timeout=2m -json ./... | tparse 11 | -------------------------------------------------------------------------------- /avroregistry/errors.go: -------------------------------------------------------------------------------- 1 | package avroregistry 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // UnavailableError reports an error when the schema registry is unavailable. 8 | type UnavailableError struct { 9 | Cause error 10 | } 11 | 12 | // Error implements the error interface. 13 | func (m *UnavailableError) Error() string { 14 | return fmt.Sprintf("schema registry unavailability caused by: %v", m.Cause) 15 | } 16 | 17 | // Unwrap unwraps and return Cause error. It is needed to properly handle and compare errors. 18 | func (e *UnavailableError) Unwrap() error { 19 | return e.Cause 20 | } 21 | -------------------------------------------------------------------------------- /avroregistry/errors_test.go: -------------------------------------------------------------------------------- 1 | package avroregistry_test 2 | 3 | import ( 4 | "errors" 5 | "testing" 6 | 7 | qt "github.com/frankban/quicktest" 8 | 9 | "github.com/heetch/avro/avroregistry" 10 | ) 11 | 12 | func TestUnavailableError_Unwrap(t *testing.T) { 13 | c := qt.New(t) 14 | var ErrExpect = errors.New("error") 15 | 16 | err := &avroregistry.UnavailableError{ 17 | Cause: ErrExpect, 18 | } 19 | 20 | c.Assert(errors.Is(err, ErrExpect), qt.IsTrue) 21 | 22 | var newErr *avroregistry.UnavailableError 23 | c.Assert(errors.As(err, &newErr), qt.IsTrue) 24 | } 25 | 26 | func TestUnavailableError_Error(t *testing.T) { 27 | c := qt.New(t) 28 | 29 | err := &avroregistry.UnavailableError{ 30 | Cause: errors.New("ECONNREFUSED"), 31 | } 32 | 33 | c.Assert(err.Error(), qt.Equals, "schema registry unavailability caused by: ECONNREFUSED") 34 | } 35 | -------------------------------------------------------------------------------- /avroregistry/message.go: -------------------------------------------------------------------------------- 1 | package avroregistry 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/binary" 7 | "encoding/json" 8 | "fmt" 9 | 10 | "github.com/heetch/avro" 11 | ) 12 | 13 | type encodingRegistry struct { 14 | r *Registry 15 | subject string 16 | } 17 | 18 | var _ avro.EncodingRegistry = encodingRegistry{} 19 | 20 | // AppendSchemaID implements avro.EncodingRegistry.AppendSchemaID 21 | // by appending the id. 22 | // See https://docs.confluent.io/current/schema-registry/serializer-formatter.html#wire-format. 23 | func (r encodingRegistry) AppendSchemaID(buf []byte, id int64) []byte { 24 | if id < 0 || id >= 1<<32-1 { 25 | panic("schema id out of range") 26 | } 27 | n := len(buf) 28 | // Magic zero byte, then 4 bytes of schema ID. 29 | buf = append(buf, 0, 0, 0, 0, 0) 30 | binary.BigEndian.PutUint32(buf[n+1:], uint32(id)) 31 | return buf 32 | } 33 | 34 | // IDForSchema implements avro.EncodingRegistry.IDForSchema 35 | // by fetching the schema ID from the registry server. 36 | // 37 | // See https://docs.confluent.io/current/schema-registry/develop/api.html#post--subjects-(string-%20subject). 38 | func (r encodingRegistry) IDForSchema(ctx context.Context, schema *avro.Type) (int64, error) { 39 | data, err := json.Marshal(struct { 40 | Schema string `json:"schema"` 41 | }{canonical(schema)}) 42 | if err != nil { 43 | return 0, err 44 | } 45 | req := r.r.newRequest(ctx, "POST", "/subjects/"+r.subject, bytes.NewReader(data)) 46 | 47 | var resp Schema 48 | if err := r.r.doRequest(req, &resp); err != nil { 49 | return 0, err 50 | } 51 | // TODO could check that the subject is the same as r.params.Subject. 52 | return resp.ID, nil 53 | } 54 | 55 | type decodingRegistry struct { 56 | r *Registry 57 | } 58 | 59 | var _ avro.DecodingRegistry = decodingRegistry{} 60 | 61 | // DecodeSchemaID implements avro.DecodingRegistry.DecodeSchemaID 62 | // by stripping off the schema-identifier header. 63 | // 64 | // See https://docs.confluent.io/current/schema-registry/serializer-formatter.html#wire-format. 65 | func (r decodingRegistry) DecodeSchemaID(msg []byte) (int64, []byte) { 66 | if len(msg) < 5 || msg[0] != 0 { 67 | return 0, nil 68 | } 69 | return int64(binary.BigEndian.Uint32(msg[1:5])), msg[5:] 70 | } 71 | 72 | // SchemaForID implements avro.DecodingRegistry.SchemaForID 73 | // by fetching the schema from the registry server. 74 | // 75 | // See https://docs.confluent.io/current/schema-registry/develop/api.html#get--schemas-ids-int-%20id 76 | func (r decodingRegistry) SchemaForID(ctx context.Context, id int64) (*avro.Type, error) { 77 | req := r.r.newRequest(ctx, "GET", fmt.Sprintf("/schemas/ids/%d", id), nil) 78 | var resp struct { 79 | Schema string `json:"schema"` 80 | } 81 | if err := r.r.doRequest(req, &resp); err != nil { 82 | return nil, err 83 | } 84 | t, err := avro.ParseType(resp.Schema) 85 | if err != nil { 86 | return nil, fmt.Errorf("invalid schema (%q) in response: %v", resp.Schema, err) 87 | } 88 | return t, nil 89 | } 90 | -------------------------------------------------------------------------------- /avroregistrytest/avroregistrytest.go: -------------------------------------------------------------------------------- 1 | package avroregistrytest 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/heetch/avro" 9 | "github.com/heetch/avro/avroregistry" 10 | ) 11 | 12 | // Register an avro type in a registry for a particular topic and then delete the subject at the end of the test. 13 | // 14 | // The following environment variables can be used to 15 | // configure the connection parameters: 16 | // 17 | // - $KAFKA_REGISTRY_ADDR 18 | // The Kafka registry address in host:port 19 | // form. If this is empty, localhost:8084 will be used. 20 | // 21 | // This requires go1.14 or higher 22 | func Register(ctx context.Context, t T, x interface{}, topic string) error { 23 | registryAddr := os.Getenv("KAFKA_REGISTRY_ADDR") 24 | if registryAddr == "" { 25 | registryAddr = "localhost:8084" 26 | } 27 | 28 | registry, err := avroregistry.New(avroregistry.Params{ 29 | ServerURL: "http://" + registryAddr, 30 | }) 31 | if err != nil { 32 | return fmt.Errorf("cannot connect to registry: %w", err) 33 | } 34 | 35 | avroType, err := avro.TypeOf(x) 36 | if err != nil { 37 | return fmt.Errorf("cannot generate Avro schema for %T: %w", x, err) 38 | } 39 | 40 | _, err = registry.Register(ctx, topic, avroType) 41 | if err != nil { 42 | return fmt.Errorf("cannot register %T in %v: %w", x, topic, err) 43 | } 44 | 45 | t.Cleanup(func() { 46 | err := registry.DeleteSubject(ctx, topic) 47 | if err != nil { 48 | t.Errorf("cannot delete subject %v: %v", topic, err) 49 | } 50 | }) 51 | 52 | return nil 53 | } 54 | 55 | // T represents a test (the usual implementation being *testing.T). 56 | type T interface { 57 | Cleanup(f func()) 58 | Errorf(f string, a ...interface{}) 59 | } 60 | -------------------------------------------------------------------------------- /avroregistrytest/avroregistrytest_test.go: -------------------------------------------------------------------------------- 1 | // +build go1.14 2 | 3 | package avroregistrytest 4 | 5 | import ( 6 | "context" 7 | "crypto/rand" 8 | "fmt" 9 | "testing" 10 | 11 | qt "github.com/frankban/quicktest" 12 | ) 13 | 14 | type x struct { 15 | Int int 16 | Str string 17 | } 18 | 19 | func TestRegister(t *testing.T) { 20 | c := qt.New(t) 21 | 22 | c.Run("OK", func(c *qt.C) { 23 | err := Register(context.Background(), c, x{}, randomName("test-")) 24 | c.Assert(err, qt.IsNil) 25 | }) 26 | 27 | c.Run("NOK - Wrong interface", func(c *qt.C) { 28 | err := Register(context.Background(), c, struct{}{}, randomName("test-")) 29 | c.Assert(err, qt.Not(qt.IsNil)) 30 | c.Assert(err, qt.ErrorMatches, "cannot generate Avro schema for.*") 31 | }) 32 | 33 | c.Run("NOK - Wrong addr", func(c *qt.C) { 34 | c.Setenv("KAFKA_REGISTRY_ADDR", "-host:1234") 35 | err := Register(context.Background(), c, x{}, randomName("test-")) 36 | c.Assert(err, qt.Not(qt.IsNil)) 37 | c.Assert(err, qt.ErrorMatches, "cannot register.*") 38 | }) 39 | } 40 | 41 | func randomName(prefix string) string { 42 | buf := make([]byte, 8) 43 | if _, err := rand.Read(buf); err != nil { 44 | panic(err) 45 | } 46 | return fmt.Sprintf("%s%x", prefix, buf) 47 | } 48 | -------------------------------------------------------------------------------- /avrotypegen/typeinfo.go: -------------------------------------------------------------------------------- 1 | // Package avrotypegen holds types that are used by generated Avro Go code. 2 | // This is an implementation detail and this might change over time. 3 | package avrotypegen 4 | 5 | import "fmt" 6 | 7 | // AvroRecord is implemented by Go types generated 8 | // by the avrogo command. 9 | type AvroRecord interface { 10 | AvroRecord() RecordInfo 11 | } 12 | 13 | // RecordInfo holds information about how a Go type relates 14 | // to an Avro schema. 15 | type RecordInfo struct { 16 | // Schema holds the Avro schema of the record. 17 | Schema string 18 | 19 | // Required holds whether fields are required. 20 | // If a field is required, it has no default value. 21 | Required []bool 22 | 23 | // Defaults holds default values for the fields. 24 | // Each item corresponds to the field at that index and returns 25 | // a newly created default value for the field. 26 | // An entry is only consulted if Required is false for that field. 27 | // Missing or nil entries are assumed to default to the zero 28 | // value for the type. 29 | Defaults []func() interface{} 30 | 31 | // Unions holds entries for union fields. 32 | // Each item corresponds to the field at that index 33 | // and holds slice with one value for each member 34 | // of the union, of type *T, where T is the type used 35 | // for that member of the union. 36 | Unions []UnionInfo 37 | } 38 | 39 | type UnionInfo struct { 40 | // Type holds a value of type *T where T is 41 | // the type described by the TypeInfo, 42 | // except when the TypeInfo represents the null 43 | // type, in which case Type will be nil. 44 | Type interface{} 45 | 46 | // When the UnionInfo describes a union, 47 | // Union holds an entry for each member 48 | // of the union. 49 | // The info can be omitted if Type is a pointer 50 | // and the union is ["null", T]. 51 | Union []UnionInfo 52 | } 53 | 54 | // Null represents the Avro null type. Its only JSON representation is null. 55 | type Null struct{} 56 | 57 | // UnmarshalJSON implements json.Unmarshaler by requiring 58 | // the JSON value to be null. 59 | func (Null) UnmarshalJSON(data []byte) error { 60 | if string(data) != "null" { 61 | return fmt.Errorf("cannot unmarshal %q into avro.Null", data) 62 | } 63 | return nil 64 | } 65 | 66 | // MarshalJSON implements json.Marshaler by returning "null". 67 | func (Null) MarshalJSON() ([]byte, error) { 68 | return []byte("null"), nil 69 | } 70 | -------------------------------------------------------------------------------- /bench_test.go: -------------------------------------------------------------------------------- 1 | package avro_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | qt "github.com/frankban/quicktest" 8 | "github.com/heetch/avro" 9 | ) 10 | 11 | func BenchmarkMarshal(b *testing.B) { 12 | type R struct { 13 | A *string 14 | B *string 15 | C []int 16 | } 17 | type T struct { 18 | R R 19 | } 20 | x := T{ 21 | R: R{ 22 | A: newString("hello"), 23 | B: newString("goodbye"), 24 | C: []int{1, 3, 1 << 20}, 25 | }, 26 | } 27 | for i := 0; i < b.N; i++ { 28 | _, _, err := avro.Marshal(x) 29 | if err != nil { 30 | b.Fatal(err) 31 | } 32 | } 33 | } 34 | 35 | func BenchmarkSingleDecoderUnmarshal(b *testing.B) { 36 | c := qt.New(b) 37 | type R struct { 38 | A *string 39 | B *string 40 | C []int 41 | } 42 | type T struct { 43 | R R 44 | } 45 | at, err := avro.TypeOf(T{}) 46 | c.Assert(err, qt.Equals, nil) 47 | r := memRegistry{ 48 | 1: at, 49 | } 50 | enc := avro.NewSingleEncoder(r, nil) 51 | ctx := context.Background() 52 | data, err := enc.Marshal(ctx, T{ 53 | R: R{ 54 | A: newString("hello"), 55 | B: newString("goodbye"), 56 | C: []int{1, 3, 1 << 20}, 57 | }, 58 | }) 59 | c.Assert(err, qt.Equals, nil) 60 | 61 | dec := avro.NewSingleDecoder(r, nil) 62 | b.ResetTimer() 63 | for i := 0; i < b.N; i++ { 64 | var x T 65 | _, err := dec.Unmarshal(ctx, data, &x) 66 | if err != nil { 67 | b.Fatal(err) 68 | } 69 | } 70 | } 71 | 72 | func newString(s string) *string { 73 | return &s 74 | } 75 | -------------------------------------------------------------------------------- /benchschema.avsc: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cmd/avrogo/avrotypemap/typemap_test.go: -------------------------------------------------------------------------------- 1 | package avrotypemap_test 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | qt "github.com/frankban/quicktest" 8 | 9 | "github.com/heetch/avro/cmd/avrogo/avrotypemap" 10 | ) 11 | 12 | //go:generate avrogo union.avsc 13 | 14 | func TestTypeInfo(t *testing.T) { 15 | c := qt.New(t) 16 | 17 | type A struct { 18 | F int 19 | } 20 | 21 | type B struct { 22 | Array []A 23 | Map map[string]A 24 | } 25 | 26 | type C struct { 27 | F B 28 | G A 29 | } 30 | 31 | m, err := avrotypemap.AvroTypeMap(reflect.TypeOf(C{})) 32 | c.Assert(err, qt.Equals, nil) 33 | c.Assert(m, qt.DeepEquals, map[string]avrotypemap.GoType{ 34 | "A": {testPkg, "A"}, 35 | "B": {testPkg, "B"}, 36 | "C": {testPkg, "C"}, 37 | }) 38 | } 39 | 40 | const testPkg = "github.com/heetch/avro/cmd/avrogo/avrotypemap_test" 41 | 42 | func TestUnion(t *testing.T) { 43 | c := qt.New(t) 44 | m, err := avrotypemap.AvroTypeMap(reflect.TypeOf(U{})) 45 | c.Assert(err, qt.Equals, nil) 46 | c.Assert(m, qt.DeepEquals, map[string]avrotypemap.GoType{ 47 | "U": {testPkg, "U"}, 48 | "UR1": {testPkg, "UR1"}, 49 | "UR2": {testPkg, "UR2"}, 50 | }) 51 | } 52 | 53 | func TestRecursiveType(t *testing.T) { 54 | c := qt.New(t) 55 | m, err := avrotypemap.AvroTypeMap(reflect.TypeOf(Recur{})) 56 | c.Assert(err, qt.Equals, nil) 57 | c.Assert(m, qt.DeepEquals, map[string]avrotypemap.GoType{ 58 | "Recur": {testPkg, "Recur"}, 59 | }) 60 | } 61 | 62 | type Recur struct { 63 | A int 64 | R *Recur 65 | } 66 | -------------------------------------------------------------------------------- /cmd/avrogo/avrotypemap/union.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "U", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "F", 7 | "type": [ 8 | { 9 | "name": "UR1", 10 | "type": "record", 11 | "fields": [ 12 | { 13 | "name": "A", 14 | "type": "int" 15 | } 16 | ] 17 | }, 18 | { 19 | "name": "UR2", 20 | "type": "record", 21 | "fields": [ 22 | { 23 | "name": "B", 24 | "type": "int" 25 | } 26 | ] 27 | } 28 | ] 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /cmd/avrogo/avrotypemap/union_gen_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package avrotypemap_test 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type U struct { 10 | // Allowed types for interface{} value: 11 | // UR1 12 | // UR2 13 | F interface{} 14 | } 15 | 16 | // AvroRecord implements the avro.AvroRecord interface. 17 | func (U) AvroRecord() avrotypegen.RecordInfo { 18 | return avrotypegen.RecordInfo{ 19 | Schema: `{"fields":[{"name":"F","type":[{"fields":[{"name":"A","type":"int"}],"name":"UR1","type":"record"},{"fields":[{"name":"B","type":"int"}],"name":"UR2","type":"record"}]}],"name":"U","type":"record"}`, 20 | Required: []bool{ 21 | 0: true, 22 | }, 23 | Unions: []avrotypegen.UnionInfo{ 24 | 0: { 25 | Type: new(interface{}), 26 | Union: []avrotypegen.UnionInfo{{ 27 | Type: new(UR1), 28 | }, { 29 | Type: new(UR2), 30 | }}, 31 | }, 32 | }, 33 | } 34 | } 35 | 36 | type UR1 struct { 37 | A int 38 | } 39 | 40 | // AvroRecord implements the avro.AvroRecord interface. 41 | func (UR1) AvroRecord() avrotypegen.RecordInfo { 42 | return avrotypegen.RecordInfo{ 43 | Schema: `{"fields":[{"name":"A","type":"int"}],"name":"UR1","type":"record"}`, 44 | Required: []bool{ 45 | 0: true, 46 | }, 47 | } 48 | } 49 | 50 | type UR2 struct { 51 | B int 52 | } 53 | 54 | // AvroRecord implements the avro.AvroRecord interface. 55 | func (UR2) AvroRecord() avrotypegen.RecordInfo { 56 | return avrotypegen.RecordInfo{ 57 | Schema: `{"fields":[{"name":"B","type":"int"}],"name":"UR2","type":"record"}`, 58 | Required: []bool{ 59 | 0: true, 60 | }, 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /cmd/avrogo/doccomment_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | 6 | qt "github.com/frankban/quicktest" 7 | ) 8 | 9 | var docTests = []struct { 10 | testName string 11 | val interface{} 12 | indent string 13 | expect string 14 | }{{ 15 | testName: "simple-doc-string", 16 | val: docString("hello"), 17 | indent: "// ", 18 | expect: ` 19 | // hello 20 | `, 21 | }, { 22 | testName: "not-a-doc-object", 23 | val: 245, 24 | indent: "// ", 25 | expect: "", 26 | }, { 27 | testName: "multi-line", 28 | val: docString(`one line 29 | and another`), 30 | indent: "// ", 31 | expect: ` 32 | // one line 33 | // and another 34 | `, 35 | }, { 36 | testName: "empty-doc-string", 37 | val: docString(""), 38 | indent: "// ", 39 | expect: "", 40 | }, { 41 | testName: "extra-white-space", 42 | val: docString(" \n \thello\n \t "), 43 | indent: "// ", 44 | expect: ` 45 | // hello 46 | `, 47 | }, { 48 | testName: "remove-stars", 49 | val: docString("* one two three\n\t\t * four five."), 50 | indent: "// ", 51 | expect: ` 52 | // one two three 53 | // four five. 54 | `, 55 | }, { 56 | testName: "remove-stars-no-newlines", 57 | val: docString("* one two three"), 58 | indent: "// ", 59 | expect: ` 60 | // one two three 61 | `, 62 | }, { 63 | testName: "remove-stars-less-spaces", 64 | val: docString("*one two three\n\t\t*four five\n\t\t*six seven\n\t\t*eight nine."), 65 | indent: "// ", 66 | expect: ` 67 | // one two three 68 | // four five 69 | // six seven 70 | // eight nine. 71 | `, 72 | }, { 73 | testName: "different-indent", 74 | val: docString("hello"), 75 | indent: "!!", 76 | expect: ` 77 | !!hello 78 | `, 79 | }} 80 | 81 | func TestDoc(t *testing.T) { 82 | c := qt.New(t) 83 | for _, test := range docTests { 84 | c.Run(test.testName, func(c *qt.C) { 85 | c.Assert(doc(test.indent, test.val), qt.Equals, test.expect) 86 | }) 87 | } 88 | } 89 | 90 | type docString string 91 | 92 | func (d docString) Doc() string { 93 | return string(d) 94 | } 95 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/avrotestdata/testdata.go: -------------------------------------------------------------------------------- 1 | package avrotestdata 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "os" 8 | "os/exec" 9 | ) 10 | 11 | type Test struct { 12 | TestName string `json:"testName"` 13 | InSchema json.RawMessage `json:"inSchema"` 14 | OutSchema json.RawMessage `json:"outSchema"` 15 | ExtraSchemas []json.RawMessage `json:"extraSchemas"` 16 | GoType string `json:"goType"` 17 | GoTypeBody string `json:"goTypeBody"` 18 | GenerateError string `json:"generateError"` 19 | Subtests map[string]Subtest `json:"subtests"` 20 | OtherTests string `json:"otherTests"` 21 | } 22 | 23 | type Subtest struct { 24 | TestName string `json:"testName"` 25 | InData json.RawMessage `json:"inData"` 26 | OutData json.RawMessage `json:"outData"` 27 | ExpectError map[string]string `json:"expectError"` 28 | } 29 | 30 | func Load(dir string) (map[string]Test, error) { 31 | var buf bytes.Buffer 32 | cmd := exec.Command("cue", "export") 33 | cmd.Dir = dir 34 | cmd.Stderr = os.Stderr 35 | cmd.Stdout = &buf 36 | err := cmd.Run() 37 | if err != nil { 38 | return nil, fmt.Errorf("cue export failed: %v", err) 39 | } 40 | var exported struct { 41 | Tests map[string]Test `json:"tests"` 42 | } 43 | err = json.Unmarshal(buf.Bytes(), &exported) 44 | if err != nil { 45 | return nil, fmt.Errorf("cannot unmarshal test data: %v", err) 46 | } 47 | return exported.Tests, nil 48 | } 49 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/arrayDefault/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package arrayDefault 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "_", 18 | "type": "int", 19 | "default": 0 20 | } 21 | ] 22 | }`, 23 | GoType: new(R), 24 | Subtests: []testutil.RoundTripSubtest{{ 25 | TestName: "main", 26 | InDataJSON: `{ 27 | "_": 0 28 | }`, 29 | OutDataJSON: `{ 30 | "arrayOfInt": [ 31 | 2, 32 | 3, 33 | 4 34 | ] 35 | }`, 36 | }}, 37 | } 38 | 39 | func TestGeneratedCode(t *testing.T) { 40 | tests.Test(t) 41 | } 42 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/arrayDefault/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "arrayOfInt", 7 | "type": { 8 | "type": "array", 9 | "items": "int" 10 | }, 11 | "default": [ 12 | 2, 13 | 3, 14 | 4 15 | ] 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/arrayDefault/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package arrayDefault 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | ArrayOfInt []int `json:"arrayOfInt"` 11 | } 12 | 13 | // AvroRecord implements the avro.AvroRecord interface. 14 | func (R) AvroRecord() avrotypegen.RecordInfo { 15 | return avrotypegen.RecordInfo{ 16 | Schema: `{"fields":[{"default":[2,3,4],"name":"arrayOfInt","type":{"items":"int","type":"array"}}],"name":"R","type":"record"}`, 17 | Defaults: []func() interface{}{ 18 | 0: func() interface{} { 19 | return []int{2, 3, 4} 20 | }, 21 | }, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/arrayOfUnion/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package arrayOfUnion 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "F", 18 | "type": { 19 | "type": "array", 20 | "items": [ 21 | "int", 22 | "string" 23 | ] 24 | } 25 | } 26 | ] 27 | }`, 28 | GoType: new(R), 29 | Subtests: []testutil.RoundTripSubtest{{ 30 | TestName: "main", 31 | InDataJSON: `{ 32 | "F": [ 33 | { 34 | "int": 1 35 | }, 36 | { 37 | "string": "hello" 38 | } 39 | ] 40 | }`, 41 | OutDataJSON: `{ 42 | "F": [ 43 | { 44 | "int": 1 45 | }, 46 | { 47 | "string": "hello" 48 | } 49 | ] 50 | }`, 51 | }}, 52 | } 53 | 54 | func TestGeneratedCode(t *testing.T) { 55 | tests.Test(t) 56 | } 57 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/arrayOfUnion/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "F", 7 | "type": { 8 | "type": "array", 9 | "items": [ 10 | "int", 11 | "string" 12 | ] 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/arrayOfUnion/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package arrayOfUnion 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | // Allowed types for interface{} value: 11 | // int 12 | // string 13 | F []interface{} 14 | } 15 | 16 | // AvroRecord implements the avro.AvroRecord interface. 17 | func (R) AvroRecord() avrotypegen.RecordInfo { 18 | return avrotypegen.RecordInfo{ 19 | Schema: `{"fields":[{"name":"F","type":{"items":["int","string"],"type":"array"}}],"name":"R","type":"record"}`, 20 | Required: []bool{ 21 | 0: true, 22 | }, 23 | Unions: []avrotypegen.UnionInfo{ 24 | 0: { 25 | Type: new([]interface{}), 26 | Union: []avrotypegen.UnionInfo{{ 27 | Type: new(int), 28 | }, { 29 | Type: new(string), 30 | }}, 31 | }, 32 | }, 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/cloudEvent/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.heetch.Message", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "Metadata", 7 | "type": { 8 | "name": "Metadata", 9 | "type": "record", 10 | "fields": [ 11 | { 12 | "name": "CloudEvent", 13 | "type": { 14 | "name": "CloudEvent", 15 | "type": "record", 16 | "fields": [ 17 | { 18 | "name": "id", 19 | "type": "string" 20 | }, 21 | { 22 | "name": "source", 23 | "type": "string", 24 | "doc": "* source holds the\n\t\t * source of the message." 25 | }, 26 | { 27 | "name": "specversion", 28 | "type": "string" 29 | }, 30 | { 31 | "name": "time", 32 | "type": { 33 | "type": "long", 34 | "logicalType": "timestamp-micros" 35 | } 36 | } 37 | ] 38 | } 39 | } 40 | ] 41 | } 42 | } 43 | ] 44 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/cloudEvent/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package cloudEvent 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | "time" 8 | ) 9 | 10 | type CloudEvent struct { 11 | Id string `json:"id"` 12 | 13 | // source holds the 14 | // source of the message. 15 | Source string `json:"source"` 16 | Specversion string `json:"specversion"` 17 | Time time.Time `json:"time"` 18 | } 19 | 20 | // AvroRecord implements the avro.AvroRecord interface. 21 | func (CloudEvent) AvroRecord() avrotypegen.RecordInfo { 22 | return avrotypegen.RecordInfo{ 23 | Schema: `{"fields":[{"name":"id","type":"string"},{"doc":"* source holds the\n\t\t * source of the message.","name":"source","type":"string"},{"name":"specversion","type":"string"},{"name":"time","type":{"logicalType":"timestamp-micros","type":"long"}}],"name":"com.heetch.CloudEvent","type":"record"}`, 24 | Required: []bool{ 25 | 0: true, 26 | 1: true, 27 | 2: true, 28 | 3: true, 29 | }, 30 | } 31 | } 32 | 33 | type Message struct { 34 | Metadata Metadata 35 | } 36 | 37 | // AvroRecord implements the avro.AvroRecord interface. 38 | func (Message) AvroRecord() avrotypegen.RecordInfo { 39 | return avrotypegen.RecordInfo{ 40 | Schema: `{"fields":[{"name":"Metadata","type":{"fields":[{"name":"CloudEvent","type":{"fields":[{"name":"id","type":"string"},{"doc":"* source holds the\n\t\t * source of the message.","name":"source","type":"string"},{"name":"specversion","type":"string"},{"name":"time","type":{"logicalType":"timestamp-micros","type":"long"}}],"name":"CloudEvent","type":"record"}}],"name":"Metadata","type":"record"}}],"name":"com.heetch.Message","type":"record"}`, 41 | Required: []bool{ 42 | 0: true, 43 | }, 44 | } 45 | } 46 | 47 | type Metadata struct { 48 | CloudEvent CloudEvent 49 | } 50 | 51 | // AvroRecord implements the avro.AvroRecord interface. 52 | func (Metadata) AvroRecord() avrotypegen.RecordInfo { 53 | return avrotypegen.RecordInfo{ 54 | Schema: `{"fields":[{"name":"CloudEvent","type":{"fields":[{"name":"id","type":"string"},{"doc":"* source holds the\n\t\t * source of the message.","name":"source","type":"string"},{"name":"specversion","type":"string"},{"name":"time","type":{"logicalType":"timestamp-micros","type":"long"}}],"name":"CloudEvent","type":"record"}}],"name":"com.heetch.Metadata","type":"record"}`, 55 | Required: []bool{ 56 | 0: true, 57 | }, 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/duplicateRecord/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package duplicateRecord 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R1", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "F", 18 | "type": { 19 | "name": "R2", 20 | "type": "record", 21 | "fields": [ 22 | { 23 | "name": "A", 24 | "type": "string" 25 | } 26 | ] 27 | } 28 | }, 29 | { 30 | "name": "G", 31 | "type": "R2" 32 | }, 33 | { 34 | "name": "H", 35 | "type": "int" 36 | } 37 | ] 38 | }`, 39 | GoType: new(R1), 40 | Subtests: []testutil.RoundTripSubtest{{ 41 | TestName: "main", 42 | InDataJSON: `{ 43 | "F": { 44 | "A": "hello" 45 | }, 46 | "G": { 47 | "A": "goodbye" 48 | }, 49 | "H": 99 50 | }`, 51 | OutDataJSON: `{ 52 | "F": { 53 | "A": "hello" 54 | }, 55 | "G": { 56 | "A": "goodbye" 57 | }, 58 | "H": 99 59 | }`, 60 | }}, 61 | } 62 | 63 | func TestGeneratedCode(t *testing.T) { 64 | tests.Test(t) 65 | } 66 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/duplicateRecord/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R1", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "F", 7 | "type": { 8 | "name": "R2", 9 | "type": "record", 10 | "fields": [ 11 | { 12 | "name": "A", 13 | "type": "string" 14 | } 15 | ] 16 | } 17 | }, 18 | { 19 | "name": "G", 20 | "type": "R2" 21 | }, 22 | { 23 | "name": "H", 24 | "type": "int" 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/duplicateRecord/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package duplicateRecord 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R1 struct { 10 | F R2 11 | G R2 12 | H int 13 | } 14 | 15 | // AvroRecord implements the avro.AvroRecord interface. 16 | func (R1) AvroRecord() avrotypegen.RecordInfo { 17 | return avrotypegen.RecordInfo{ 18 | Schema: `{"fields":[{"name":"F","type":{"fields":[{"name":"A","type":"string"}],"name":"R2","type":"record"}},{"name":"G","type":"R2"},{"name":"H","type":"int"}],"name":"R1","type":"record"}`, 19 | Required: []bool{ 20 | 0: true, 21 | 1: true, 22 | 2: true, 23 | }, 24 | } 25 | } 26 | 27 | type R2 struct { 28 | A string 29 | } 30 | 31 | // AvroRecord implements the avro.AvroRecord interface. 32 | func (R2) AvroRecord() avrotypegen.RecordInfo { 33 | return avrotypegen.RecordInfo{ 34 | Schema: `{"fields":[{"name":"A","type":"string"}],"name":"R2","type":"record"}`, 35 | Required: []bool{ 36 | 0: true, 37 | }, 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/enumDefault/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package enumDefault 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "_", 18 | "type": "int", 19 | "default": 0 20 | } 21 | ] 22 | }`, 23 | GoType: new(R), 24 | Subtests: []testutil.RoundTripSubtest{{ 25 | TestName: "main", 26 | InDataJSON: `{ 27 | "_": 0 28 | }`, 29 | OutDataJSON: `{ 30 | "enumField": "b" 31 | }`, 32 | }}, 33 | } 34 | 35 | func TestGeneratedCode(t *testing.T) { 36 | tests.Test(t) 37 | } 38 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/enumDefault/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "enumField", 7 | "type": { 8 | "name": "Foo", 9 | "type": "enum", 10 | "symbols": [ 11 | "a", 12 | "b", 13 | "c" 14 | ] 15 | }, 16 | "default": "b" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/enumDefault/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package enumDefault 4 | 5 | import ( 6 | "fmt" 7 | "github.com/heetch/avro/avrotypegen" 8 | "strconv" 9 | ) 10 | 11 | type Foo int 12 | 13 | const ( 14 | FooA Foo = iota 15 | FooB 16 | FooC 17 | ) 18 | 19 | var _Foo_strings = []string{ 20 | "a", 21 | "b", 22 | "c", 23 | } 24 | 25 | // String returns the textual representation of Foo. 26 | func (e Foo) String() string { 27 | if e < 0 || int(e) >= len(_Foo_strings) { 28 | return "Foo(" + strconv.FormatInt(int64(e), 10) + ")" 29 | } 30 | return _Foo_strings[e] 31 | } 32 | 33 | // MarshalText implements encoding.TextMarshaler 34 | // by returning the textual representation of Foo. 35 | func (e Foo) MarshalText() ([]byte, error) { 36 | if e < 0 || int(e) >= len(_Foo_strings) { 37 | return nil, fmt.Errorf("Foo value %d is out of bounds", e) 38 | } 39 | return []byte(_Foo_strings[e]), nil 40 | } 41 | 42 | // UnmarshalText implements encoding.TextUnmarshaler 43 | // by expecting the textual representation of Foo. 44 | func (e *Foo) UnmarshalText(data []byte) error { 45 | // Note for future: this could be more efficient. 46 | for i, s := range _Foo_strings { 47 | if string(data) == s { 48 | *e = Foo(i) 49 | return nil 50 | } 51 | } 52 | return fmt.Errorf("unknown value %q for Foo", data) 53 | } 54 | 55 | type R struct { 56 | EnumField Foo `json:"enumField"` 57 | } 58 | 59 | // AvroRecord implements the avro.AvroRecord interface. 60 | func (R) AvroRecord() avrotypegen.RecordInfo { 61 | return avrotypegen.RecordInfo{ 62 | Schema: `{"fields":[{"default":"b","name":"enumField","type":{"name":"Foo","symbols":["a","b","c"],"type":"enum"}}],"name":"R","type":"record"}`, 63 | Defaults: []func() interface{}{ 64 | 0: func() interface{} { 65 | return FooB 66 | }, 67 | }, 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/fixedDefault/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package fixedDefault 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "_", 18 | "type": "int", 19 | "default": 0 20 | } 21 | ] 22 | }`, 23 | GoType: new(R), 24 | Subtests: []testutil.RoundTripSubtest{{ 25 | TestName: "main", 26 | InDataJSON: `{ 27 | "_": 0 28 | }`, 29 | OutDataJSON: `{ 30 | "fixedField": "hello" 31 | }`, 32 | }}, 33 | } 34 | 35 | func TestGeneratedCode(t *testing.T) { 36 | tests.Test(t) 37 | } 38 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/fixedDefault/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "fixedField", 7 | "type": { 8 | "name": "five", 9 | "type": "fixed", 10 | "size": 5 11 | }, 12 | "default": "hello" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/fixedDefault/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package fixedDefault 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | FixedField Five `json:"fixedField"` 11 | } 12 | 13 | // AvroRecord implements the avro.AvroRecord interface. 14 | func (R) AvroRecord() avrotypegen.RecordInfo { 15 | return avrotypegen.RecordInfo{ 16 | Schema: `{"fields":[{"default":"hello","name":"fixedField","type":{"name":"five","size":5,"type":"fixed"}}],"name":"R","type":"record"}`, 17 | Defaults: []func() interface{}{ 18 | 0: func() interface{} { 19 | return Five{0x68, 0x65, 0x6c, 0x6c, 0x6f} 20 | }, 21 | }, 22 | } 23 | } 24 | 25 | type Five [5]byte 26 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeCustomName/other_test.go: -------------------------------------------------------------------------------- 1 | package goTypeCustomName 2 | 3 | // Check that the types exist and look correct 4 | var ( 5 | _ customName 6 | _ customEnum = customEnumA 7 | _ = customFixed{}[1] 8 | ) 9 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeCustomName/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package goTypeCustomName 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "M", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "E", 18 | "type": { 19 | "name": "e", 20 | "type": "enum", 21 | "symbols": [ 22 | "a", 23 | "b" 24 | ], 25 | "go.name": "customEnum" 26 | } 27 | }, 28 | { 29 | "name": "F", 30 | "type": { 31 | "name": "f", 32 | "type": "fixed", 33 | "size": 2, 34 | "go.name": "customFixed" 35 | } 36 | } 37 | ], 38 | "go.name": "customName" 39 | }`, 40 | GoType: new(customName), 41 | Subtests: []testutil.RoundTripSubtest{{ 42 | TestName: "main", 43 | InDataJSON: `{ 44 | "E": "b", 45 | "F": "xz" 46 | }`, 47 | OutDataJSON: `{ 48 | "E": "b", 49 | "F": "xz" 50 | }`, 51 | }}, 52 | } 53 | 54 | func TestGeneratedCode(t *testing.T) { 55 | tests.Test(t) 56 | } 57 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeCustomName/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "M", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "E", 7 | "type": { 8 | "name": "e", 9 | "type": "enum", 10 | "symbols": [ 11 | "a", 12 | "b" 13 | ], 14 | "go.name": "customEnum" 15 | } 16 | }, 17 | { 18 | "name": "F", 19 | "type": { 20 | "name": "f", 21 | "type": "fixed", 22 | "size": 2, 23 | "go.name": "customFixed" 24 | } 25 | } 26 | ], 27 | "go.name": "customName" 28 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeCustomName/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package goTypeCustomName 4 | 5 | import ( 6 | "fmt" 7 | "github.com/heetch/avro/avrotypegen" 8 | "strconv" 9 | ) 10 | 11 | type customName struct { 12 | E customEnum 13 | F customFixed 14 | } 15 | 16 | // AvroRecord implements the avro.AvroRecord interface. 17 | func (customName) AvroRecord() avrotypegen.RecordInfo { 18 | return avrotypegen.RecordInfo{ 19 | Schema: `{"fields":[{"name":"E","type":{"go.name":"customEnum","name":"e","symbols":["a","b"],"type":"enum"}},{"name":"F","type":{"go.name":"customFixed","name":"f","size":2,"type":"fixed"}}],"go.name":"customName","name":"M","type":"record"}`, 20 | Required: []bool{ 21 | 0: true, 22 | 1: true, 23 | }, 24 | } 25 | } 26 | 27 | type customEnum int 28 | 29 | const ( 30 | customEnumA customEnum = iota 31 | customEnumB 32 | ) 33 | 34 | var _customEnum_strings = []string{ 35 | "a", 36 | "b", 37 | } 38 | 39 | // String returns the textual representation of customEnum. 40 | func (e customEnum) String() string { 41 | if e < 0 || int(e) >= len(_customEnum_strings) { 42 | return "customEnum(" + strconv.FormatInt(int64(e), 10) + ")" 43 | } 44 | return _customEnum_strings[e] 45 | } 46 | 47 | // MarshalText implements encoding.TextMarshaler 48 | // by returning the textual representation of customEnum. 49 | func (e customEnum) MarshalText() ([]byte, error) { 50 | if e < 0 || int(e) >= len(_customEnum_strings) { 51 | return nil, fmt.Errorf("customEnum value %d is out of bounds", e) 52 | } 53 | return []byte(_customEnum_strings[e]), nil 54 | } 55 | 56 | // UnmarshalText implements encoding.TextUnmarshaler 57 | // by expecting the textual representation of E. 58 | func (e *customEnum) UnmarshalText(data []byte) error { 59 | // Note for future: this could be more efficient. 60 | for i, s := range _customEnum_strings { 61 | if string(data) == s { 62 | *e = customEnum(i) 63 | return nil 64 | } 65 | } 66 | return fmt.Errorf("unknown value %q for customEnum", data) 67 | } 68 | 69 | type customFixed [2]byte 70 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeExternal/other_test.go: -------------------------------------------------------------------------------- 1 | package goTypeExternal 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | qt "github.com/frankban/quicktest" 8 | 9 | "github.com/heetch/avro/internal/testtypes" 10 | ) 11 | 12 | var ( 13 | messageType = reflect.TypeOf(testtypes.Message{}) 14 | cloudEventType = reflect.TypeOf(testtypes.CloudEvent{}) 15 | ) 16 | 17 | func TestCorrectTypes(t *testing.T) { 18 | c := qt.New(t) 19 | var r R 20 | c.Assert(reflect.TypeOf(r.F), qt.Equals, messageType) 21 | c.Assert(reflect.TypeOf(r.G), qt.Equals, cloudEventType) 22 | } 23 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeExternal/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package goTypeExternal 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | "github.com/heetch/avro/internal/testtypes" 8 | ) 9 | 10 | type R struct { 11 | F testtypes.Message 12 | G testtypes.CloudEvent 13 | H string 14 | } 15 | 16 | // AvroRecord implements the avro.AvroRecord interface. 17 | func (R) AvroRecord() avrotypegen.RecordInfo { 18 | return avrotypegen.RecordInfo{ 19 | Schema: `{"fields":[{"name":"F","type":{"fields":[{"name":"Metadata","type":{"fields":[{"name":"CloudEvent","type":{"fields":[{"name":"id","type":"string"},{"name":"source","type":"string"},{"name":"specversion","type":"string"},{"name":"time","type":{"logicalType":"timestamp-micros","type":"long"}}],"name":"CloudEvent","type":"record"}}],"name":"Metadata","type":"record"}}],"go.package":"github.com/heetch/avro/internal/testtypes","name":"com.heetch.Message","type":"record"}},{"name":"G","type":"com.heetch.CloudEvent"},{"name":"H","type":"string"}],"name":"R","type":"record"}`, 20 | Required: []bool{ 21 | 0: true, 22 | 1: true, 23 | 2: true, 24 | }, 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeFieldsOmitted/dummy.go: -------------------------------------------------------------------------------- 1 | package goTypeFieldsOmitted 2 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeFieldsOmitted/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package goTypeFieldsOmitted 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [] 16 | }`, 17 | GoType: new(R), 18 | Subtests: []testutil.RoundTripSubtest{{ 19 | TestName: "main", 20 | InDataJSON: `{}`, 21 | OutDataJSON: `{ 22 | "E": [], 23 | "A": 0, 24 | "F": { 25 | "A": 0, 26 | "B": "" 27 | }, 28 | "B": "", 29 | "C": "\u0000\u0000\u0000", 30 | "D": {} 31 | }`, 32 | }}, 33 | } 34 | 35 | type R struct { 36 | A int 37 | B string 38 | C [3]byte 39 | D map[string]string 40 | E []string 41 | F T 42 | } 43 | type T struct { 44 | A int 45 | B string 46 | } 47 | 48 | func TestGeneratedCode(t *testing.T) { 49 | tests.Test(t) 50 | } 51 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeFixed/dummy.go: -------------------------------------------------------------------------------- 1 | package goTypeFixed 2 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeFixed/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package goTypeFixed 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "A", 18 | "type": { 19 | "name": "go.Fixed3", 20 | "type": "fixed", 21 | "size": 3 22 | } 23 | } 24 | ] 25 | }`, 26 | GoType: new(R), 27 | Subtests: []testutil.RoundTripSubtest{{ 28 | TestName: "main", 29 | InDataJSON: `{ 30 | "A": "abc" 31 | }`, 32 | OutDataJSON: `{ 33 | "A": "abc" 34 | }`, 35 | }}, 36 | } 37 | 38 | type R struct { 39 | A [3]byte 40 | } 41 | 42 | func TestGeneratedCode(t *testing.T) { 43 | tests.Test(t) 44 | } 45 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeMap/dummy.go: -------------------------------------------------------------------------------- 1 | package goTypeMap 2 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeMap/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package goTypeMap 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "A", 18 | "type": { 19 | "type": "map", 20 | "values": "string" 21 | } 22 | } 23 | ] 24 | }`, 25 | GoType: new(R), 26 | Subtests: []testutil.RoundTripSubtest{{ 27 | TestName: "empty", 28 | InDataJSON: `{ 29 | "A": {} 30 | }`, 31 | OutDataJSON: `{ 32 | "A": {} 33 | }`, 34 | }, { 35 | TestName: "non_empty", 36 | InDataJSON: `{ 37 | "A": { 38 | "a": "b", 39 | "c": "d" 40 | } 41 | }`, 42 | OutDataJSON: `{ 43 | "A": { 44 | "a": "b", 45 | "c": "d" 46 | } 47 | }`, 48 | }}, 49 | } 50 | 51 | type R struct { 52 | A map[string]string 53 | } 54 | 55 | func TestGeneratedCode(t *testing.T) { 56 | tests.Test(t) 57 | } 58 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeMultipleFields/dummy.go: -------------------------------------------------------------------------------- 1 | package goTypeMultipleFields 2 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeMultipleFields/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package goTypeMultipleFields 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "A", 18 | "type": "int" 19 | }, 20 | { 21 | "name": "B", 22 | "type": "int" 23 | } 24 | ] 25 | }`, 26 | GoType: new(R), 27 | Subtests: []testutil.RoundTripSubtest{{ 28 | TestName: "main", 29 | InDataJSON: `{ 30 | "A": 1, 31 | "B": 2 32 | }`, 33 | OutDataJSON: `{ 34 | "A": 1, 35 | "B": 2 36 | }`, 37 | }}, 38 | } 39 | 40 | type R struct { 41 | B int 42 | A int 43 | } 44 | 45 | func TestGeneratedCode(t *testing.T) { 46 | tests.Test(t) 47 | } 48 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypePointer/dummy.go: -------------------------------------------------------------------------------- 1 | package goTypePointer 2 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypePointer/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package goTypePointer 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "A", 18 | "type": [ 19 | "null", 20 | "long" 21 | ] 22 | } 23 | ] 24 | }`, 25 | GoType: new(R), 26 | Subtests: []testutil.RoundTripSubtest{{ 27 | TestName: "non_null", 28 | InDataJSON: `{ 29 | "A": { 30 | "long": 99 31 | } 32 | }`, 33 | OutDataJSON: `{ 34 | "A": { 35 | "long": 99 36 | } 37 | }`, 38 | }, { 39 | TestName: "null", 40 | InDataJSON: `{ 41 | "A": null 42 | }`, 43 | OutDataJSON: `{ 44 | "A": null 45 | }`, 46 | }}, 47 | } 48 | 49 | type R struct { 50 | A *int 51 | } 52 | 53 | func TestGeneratedCode(t *testing.T) { 54 | tests.Test(t) 55 | } 56 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeProtobufRecord/dummy.go: -------------------------------------------------------------------------------- 1 | package goTypeProtobufRecord 2 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeProtobufRecord/other_test.go: -------------------------------------------------------------------------------- 1 | package goTypeProtobufRecord 2 | 3 | import "github.com/heetch/avro/internal/testtypes" 4 | 5 | type R = testtypes.MessageB 6 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeProtobufRecord/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package goTypeProtobufRecord 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "MessageB", 14 | "type": "record", 15 | "fields": [] 16 | }`, 17 | GoType: new(R), 18 | Subtests: []testutil.RoundTripSubtest{{ 19 | TestName: "main", 20 | InDataJSON: `{}`, 21 | OutDataJSON: `{ 22 | "arble": null, 23 | "selected": false 24 | }`, 25 | }}, 26 | } 27 | 28 | func TestGeneratedCode(t *testing.T) { 29 | tests.Test(t) 30 | } 31 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeSlice/dummy.go: -------------------------------------------------------------------------------- 1 | package goTypeSlice 2 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeSlice/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package goTypeSlice 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "A", 18 | "type": { 19 | "type": "array", 20 | "items": "string" 21 | } 22 | } 23 | ] 24 | }`, 25 | GoType: new(R), 26 | Subtests: []testutil.RoundTripSubtest{{ 27 | TestName: "empty", 28 | InDataJSON: `{ 29 | "A": [] 30 | }`, 31 | OutDataJSON: `{ 32 | "A": [] 33 | }`, 34 | }, { 35 | TestName: "non_empty", 36 | InDataJSON: `{ 37 | "A": [ 38 | "a", 39 | "b", 40 | "cd" 41 | ] 42 | }`, 43 | OutDataJSON: `{ 44 | "A": [ 45 | "a", 46 | "b", 47 | "cd" 48 | ] 49 | }`, 50 | }}, 51 | } 52 | 53 | type R struct { 54 | A []string 55 | } 56 | 57 | func TestGeneratedCode(t *testing.T) { 58 | tests.Test(t) 59 | } 60 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeStruct/dummy.go: -------------------------------------------------------------------------------- 1 | package goTypeStruct 2 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/goTypeStruct/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package goTypeStruct 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "S1", 18 | "type": { 19 | "name": "T", 20 | "type": "record", 21 | "fields": [ 22 | { 23 | "name": "A", 24 | "type": "int" 25 | }, 26 | { 27 | "name": "B", 28 | "type": "string" 29 | } 30 | ] 31 | } 32 | }, 33 | { 34 | "name": "S2", 35 | "type": "T" 36 | } 37 | ] 38 | }`, 39 | GoType: new(R), 40 | Subtests: []testutil.RoundTripSubtest{{ 41 | TestName: "main", 42 | InDataJSON: `{ 43 | "S1": { 44 | "A": 12345, 45 | "B": "hello" 46 | }, 47 | "S2": { 48 | "A": 999, 49 | "B": "b" 50 | } 51 | }`, 52 | OutDataJSON: `{ 53 | "S1": { 54 | "A": 12345, 55 | "B": "hello" 56 | }, 57 | "S2": { 58 | "A": 999, 59 | "B": "b" 60 | } 61 | }`, 62 | }}, 63 | } 64 | 65 | type R struct { 66 | S1 T 67 | S2 T 68 | } 69 | type T struct { 70 | A int 71 | B string 72 | } 73 | 74 | func TestGeneratedCode(t *testing.T) { 75 | tests.Test(t) 76 | } 77 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/invalidUUID/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package invalidUUID 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "T", 18 | "type": { 19 | "type": "string", 20 | "logicalType": "uuid" 21 | } 22 | } 23 | ] 24 | }`, 25 | GoType: new(R), 26 | Subtests: []testutil.RoundTripSubtest{{ 27 | TestName: "main", 28 | InDataJSON: `{ 29 | "T": "invalid_uuid" 30 | }`, 31 | OutDataJSON: `null`, 32 | ExpectError: map[testutil.ErrorType]string{`unmarshal`: `invalid UUID in Avro encoding: invalid UUID length: 12`}, 33 | }}, 34 | } 35 | 36 | func TestGeneratedCode(t *testing.T) { 37 | tests.Test(t) 38 | } 39 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/invalidUUID/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "T", 7 | "type": { 8 | "type": "string", 9 | "logicalType": "uuid" 10 | } 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/invalidUUID/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package invalidUUID 4 | 5 | import ( 6 | uuid "github.com/google/uuid" 7 | "github.com/heetch/avro/avrotypegen" 8 | ) 9 | 10 | type R struct { 11 | T uuid.UUID 12 | } 13 | 14 | // AvroRecord implements the avro.AvroRecord interface. 15 | func (R) AvroRecord() avrotypegen.RecordInfo { 16 | return avrotypegen.RecordInfo{ 17 | Schema: `{"fields":[{"name":"T","type":{"logicalType":"uuid","type":"string"}}],"name":"R","type":"record"}`, 18 | Required: []bool{ 19 | 0: true, 20 | }, 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/justEnum/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package justEnum 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "MyEnum", 14 | "type": "enum", 15 | "symbols": [ 16 | "a", 17 | "b", 18 | "c" 19 | ] 20 | }`, 21 | GoType: new(MyEnum), 22 | Subtests: []testutil.RoundTripSubtest{{ 23 | TestName: "main", 24 | InDataJSON: `"b"`, 25 | OutDataJSON: `"b"`, 26 | }}, 27 | } 28 | 29 | func TestGeneratedCode(t *testing.T) { 30 | tests.Test(t) 31 | } 32 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/justEnum/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MyEnum", 3 | "type": "enum", 4 | "symbols": [ 5 | "a", 6 | "b", 7 | "c" 8 | ] 9 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/justEnum/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package justEnum 4 | 5 | import ( 6 | "fmt" 7 | "strconv" 8 | ) 9 | 10 | type MyEnum int 11 | 12 | const ( 13 | MyEnumA MyEnum = iota 14 | MyEnumB 15 | MyEnumC 16 | ) 17 | 18 | var _MyEnum_strings = []string{ 19 | "a", 20 | "b", 21 | "c", 22 | } 23 | 24 | // String returns the textual representation of MyEnum. 25 | func (e MyEnum) String() string { 26 | if e < 0 || int(e) >= len(_MyEnum_strings) { 27 | return "MyEnum(" + strconv.FormatInt(int64(e), 10) + ")" 28 | } 29 | return _MyEnum_strings[e] 30 | } 31 | 32 | // MarshalText implements encoding.TextMarshaler 33 | // by returning the textual representation of MyEnum. 34 | func (e MyEnum) MarshalText() ([]byte, error) { 35 | if e < 0 || int(e) >= len(_MyEnum_strings) { 36 | return nil, fmt.Errorf("MyEnum value %d is out of bounds", e) 37 | } 38 | return []byte(_MyEnum_strings[e]), nil 39 | } 40 | 41 | // UnmarshalText implements encoding.TextUnmarshaler 42 | // by expecting the textual representation of MyEnum. 43 | func (e *MyEnum) UnmarshalText(data []byte) error { 44 | // Note for future: this could be more efficient. 45 | for i, s := range _MyEnum_strings { 46 | if string(data) == s { 47 | *e = MyEnum(i) 48 | return nil 49 | } 50 | } 51 | return fmt.Errorf("unknown value %q for MyEnum", data) 52 | } 53 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/linkedList/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package linkedList 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "List", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "Item", 18 | "type": "int" 19 | }, 20 | { 21 | "name": "Next", 22 | "type": [ 23 | "null", 24 | "List" 25 | ], 26 | "default": null 27 | } 28 | ] 29 | }`, 30 | GoType: new(List), 31 | Subtests: []testutil.RoundTripSubtest{{ 32 | TestName: "main", 33 | InDataJSON: `{ 34 | "Item": 1234, 35 | "Next": { 36 | "List": { 37 | "Item": 9999, 38 | "Next": null 39 | } 40 | } 41 | }`, 42 | OutDataJSON: `{ 43 | "Item": 1234, 44 | "Next": { 45 | "List": { 46 | "Item": 9999, 47 | "Next": null 48 | } 49 | } 50 | }`, 51 | }}, 52 | } 53 | 54 | func TestGeneratedCode(t *testing.T) { 55 | tests.Test(t) 56 | } 57 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/linkedList/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "List", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "Item", 7 | "type": "int" 8 | }, 9 | { 10 | "name": "Next", 11 | "type": [ 12 | "null", 13 | "List" 14 | ], 15 | "default": null 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/linkedList/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package linkedList 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type List struct { 10 | Item int 11 | Next *List 12 | } 13 | 14 | // AvroRecord implements the avro.AvroRecord interface. 15 | func (List) AvroRecord() avrotypegen.RecordInfo { 16 | return avrotypegen.RecordInfo{ 17 | Schema: `{"fields":[{"name":"Item","type":"int"},{"default":null,"name":"Next","type":["null","List"]}],"name":"List","type":"record"}`, 18 | Required: []bool{ 19 | 0: true, 20 | }, 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/linkedListThenSomethingElse/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package linkedListThenSomethingElse 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "L", 18 | "type": { 19 | "name": "List", 20 | "type": "record", 21 | "fields": [ 22 | { 23 | "name": "Item", 24 | "type": "int" 25 | }, 26 | { 27 | "name": "Next", 28 | "type": [ 29 | "null", 30 | "List" 31 | ], 32 | "default": null 33 | } 34 | ] 35 | } 36 | }, 37 | { 38 | "name": "M", 39 | "type": "int" 40 | } 41 | ] 42 | }`, 43 | GoType: new(R), 44 | Subtests: []testutil.RoundTripSubtest{{ 45 | TestName: "main", 46 | InDataJSON: `{ 47 | "M": 1234, 48 | "L": { 49 | "Item": 1234, 50 | "Next": { 51 | "List": { 52 | "Item": 9999, 53 | "Next": null 54 | } 55 | } 56 | } 57 | }`, 58 | OutDataJSON: `{ 59 | "M": 1234, 60 | "L": { 61 | "Item": 1234, 62 | "Next": { 63 | "List": { 64 | "Item": 9999, 65 | "Next": null 66 | } 67 | } 68 | } 69 | }`, 70 | }}, 71 | } 72 | 73 | func TestGeneratedCode(t *testing.T) { 74 | tests.Test(t) 75 | } 76 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/linkedListThenSomethingElse/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "L", 7 | "type": { 8 | "name": "List", 9 | "type": "record", 10 | "fields": [ 11 | { 12 | "name": "Item", 13 | "type": "int" 14 | }, 15 | { 16 | "name": "Next", 17 | "type": [ 18 | "null", 19 | "List" 20 | ], 21 | "default": null 22 | } 23 | ] 24 | } 25 | }, 26 | { 27 | "name": "M", 28 | "type": "int" 29 | } 30 | ] 31 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/linkedListThenSomethingElse/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package linkedListThenSomethingElse 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type List struct { 10 | Item int 11 | Next *List 12 | } 13 | 14 | // AvroRecord implements the avro.AvroRecord interface. 15 | func (List) AvroRecord() avrotypegen.RecordInfo { 16 | return avrotypegen.RecordInfo{ 17 | Schema: `{"fields":[{"name":"Item","type":"int"},{"default":null,"name":"Next","type":["null","List"]}],"name":"List","type":"record"}`, 18 | Required: []bool{ 19 | 0: true, 20 | }, 21 | } 22 | } 23 | 24 | type R struct { 25 | L List 26 | M int 27 | } 28 | 29 | // AvroRecord implements the avro.AvroRecord interface. 30 | func (R) AvroRecord() avrotypegen.RecordInfo { 31 | return avrotypegen.RecordInfo{ 32 | Schema: `{"fields":[{"name":"L","type":{"fields":[{"name":"Item","type":"int"},{"default":null,"name":"Next","type":["null","List"]}],"name":"List","type":"record"}},{"name":"M","type":"int"}],"name":"R","type":"record"}`, 33 | Required: []bool{ 34 | 0: true, 35 | 1: true, 36 | }, 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/mapDefault/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package mapDefault 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "_", 18 | "type": "int", 19 | "default": 0 20 | } 21 | ] 22 | }`, 23 | GoType: new(R), 24 | Subtests: []testutil.RoundTripSubtest{{ 25 | TestName: "main", 26 | InDataJSON: `{ 27 | "_": 0 28 | }`, 29 | OutDataJSON: `{ 30 | "mapOfInt": { 31 | "a": 2, 32 | "b": 5, 33 | "c": 99 34 | } 35 | }`, 36 | }}, 37 | } 38 | 39 | func TestGeneratedCode(t *testing.T) { 40 | tests.Test(t) 41 | } 42 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/mapDefault/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "mapOfInt", 7 | "type": { 8 | "type": "map", 9 | "values": "int" 10 | }, 11 | "default": { 12 | "a": 2, 13 | "b": 5, 14 | "c": 99 15 | } 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/mapDefault/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package mapDefault 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | MapOfInt map[string]int `json:"mapOfInt"` 11 | } 12 | 13 | // AvroRecord implements the avro.AvroRecord interface. 14 | func (R) AvroRecord() avrotypegen.RecordInfo { 15 | return avrotypegen.RecordInfo{ 16 | Schema: `{"fields":[{"default":{"a":2,"b":5,"c":99},"name":"mapOfInt","type":{"type":"map","values":"int"}}],"name":"R","type":"record"}`, 17 | Defaults: []func() interface{}{ 18 | 0: func() interface{} { 19 | return map[string]int{ 20 | "a": 2, 21 | "b": 5, 22 | "c": 99, 23 | } 24 | }, 25 | }, 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/multiSchema/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package multiSchema 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "F", 18 | "type": { 19 | "name": "S", 20 | "type": "record", 21 | "fields": [ 22 | { 23 | "name": "G", 24 | "type": "int" 25 | } 26 | ] 27 | } 28 | } 29 | ] 30 | }`, 31 | GoType: new(R), 32 | Subtests: []testutil.RoundTripSubtest{{ 33 | TestName: "main", 34 | InDataJSON: `{ 35 | "F": { 36 | "G": 99 37 | } 38 | }`, 39 | OutDataJSON: `{ 40 | "F": { 41 | "G": 99 42 | } 43 | }`, 44 | }}, 45 | } 46 | 47 | func TestGeneratedCode(t *testing.T) { 48 | tests.Test(t) 49 | } 50 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/multiSchema/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "F", 7 | "type": "S" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/multiSchema/schema1.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "S", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "G", 7 | "type": "int" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/multiSchema/schema1_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package multiSchema 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type S struct { 10 | G int 11 | } 12 | 13 | // AvroRecord implements the avro.AvroRecord interface. 14 | func (S) AvroRecord() avrotypegen.RecordInfo { 15 | return avrotypegen.RecordInfo{ 16 | Schema: `{"fields":[{"name":"G","type":"int"}],"name":"S","type":"record"}`, 17 | Required: []bool{ 18 | 0: true, 19 | }, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/multiSchema/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package multiSchema 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | F S 11 | } 12 | 13 | // AvroRecord implements the avro.AvroRecord interface. 14 | func (R) AvroRecord() avrotypegen.RecordInfo { 15 | return avrotypegen.RecordInfo{ 16 | Schema: `{"fields":[{"name":"F","type":{"fields":[{"name":"G","type":"int"}],"name":"S","type":"record"}}],"name":"R","type":"record"}`, 17 | Required: []bool{ 18 | 0: true, 19 | }, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/multiSchemaExternalType/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "F", 7 | "type": "com.heetch.Message" 8 | }, 9 | { 10 | "name": "G", 11 | "type": "com.heetch.CloudEvent" 12 | }, 13 | { 14 | "name": "H", 15 | "type": "string" 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/multiSchemaExternalType/schema1.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.heetch.Message", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "Metadata", 7 | "type": { 8 | "name": "Metadata", 9 | "type": "record", 10 | "fields": [ 11 | { 12 | "name": "CloudEvent", 13 | "type": { 14 | "name": "CloudEvent", 15 | "type": "record", 16 | "fields": [ 17 | { 18 | "name": "id", 19 | "type": "string" 20 | }, 21 | { 22 | "name": "source", 23 | "type": "string" 24 | }, 25 | { 26 | "name": "specversion", 27 | "type": "string" 28 | }, 29 | { 30 | "name": "time", 31 | "type": { 32 | "type": "long", 33 | "logicalType": "timestamp-micros" 34 | } 35 | } 36 | ] 37 | } 38 | } 39 | ] 40 | } 41 | } 42 | ], 43 | "go.package": "github.com/heetch/avro/internal/testtypes" 44 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/multiSchemaExternalType/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package multiSchemaExternalType 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | "github.com/heetch/avro/internal/testtypes" 8 | ) 9 | 10 | type R struct { 11 | F testtypes.Message 12 | G testtypes.CloudEvent 13 | H string 14 | } 15 | 16 | // AvroRecord implements the avro.AvroRecord interface. 17 | func (R) AvroRecord() avrotypegen.RecordInfo { 18 | return avrotypegen.RecordInfo{ 19 | Schema: `{"fields":[{"name":"F","type":{"fields":[{"name":"Metadata","type":{"fields":[{"name":"CloudEvent","type":{"fields":[{"name":"id","type":"string"},{"name":"source","type":"string"},{"name":"specversion","type":"string"},{"name":"time","type":{"logicalType":"timestamp-micros","type":"long"}}],"name":"CloudEvent","type":"record"}}],"name":"Metadata","type":"record"}}],"go.package":"github.com/heetch/avro/internal/testtypes","name":"com.heetch.Message","type":"record"}},{"name":"G","type":"com.heetch.CloudEvent"},{"name":"H","type":"string"}],"name":"R","type":"record"}`, 20 | Required: []bool{ 21 | 0: true, 22 | 1: true, 23 | 2: true, 24 | }, 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/multiSchemaMutualRecursive/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "F", 7 | "type": { 8 | "type": "array", 9 | "items": "S" 10 | }, 11 | "default": [] 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/multiSchemaMutualRecursive/schema1.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "S", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "Data", 7 | "type": "string", 8 | "default": "" 9 | }, 10 | { 11 | "name": "Child", 12 | "type": [ 13 | "null", 14 | "R" 15 | ], 16 | "default": null 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/multiSchemaMutualRecursive/schema1_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package multiSchemaMutualRecursive 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type S struct { 10 | Data string 11 | Child *R 12 | } 13 | 14 | // AvroRecord implements the avro.AvroRecord interface. 15 | func (S) AvroRecord() avrotypegen.RecordInfo { 16 | return avrotypegen.RecordInfo{ 17 | Schema: `{"fields":[{"default":"","name":"Data","type":"string"},{"default":null,"name":"Child","type":["null",{"fields":[{"default":[],"name":"F","type":{"items":"S","type":"array"}}],"name":"R","type":"record"}]}],"name":"S","type":"record"}`, 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/multiSchemaMutualRecursive/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package multiSchemaMutualRecursive 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | F []S 11 | } 12 | 13 | // AvroRecord implements the avro.AvroRecord interface. 14 | func (R) AvroRecord() avrotypegen.RecordInfo { 15 | return avrotypegen.RecordInfo{ 16 | Schema: `{"fields":[{"default":[],"name":"F","type":{"items":{"fields":[{"default":"","name":"Data","type":"string"},{"default":null,"name":"Child","type":["null","R"]}],"name":"S","type":"record"},"type":"array"}}],"name":"R","type":"record"}`, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/nestedUnion/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package nestedUnion 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "F", 18 | "type": { 19 | "type": "array", 20 | "items": [ 21 | "int", 22 | { 23 | "type": "array", 24 | "items": [ 25 | "null", 26 | "string" 27 | ] 28 | } 29 | ] 30 | } 31 | } 32 | ] 33 | }`, 34 | GoType: new(R), 35 | Subtests: []testutil.RoundTripSubtest{{ 36 | TestName: "main", 37 | InDataJSON: `{ 38 | "F": [ 39 | { 40 | "int": 1 41 | }, 42 | { 43 | "array": [ 44 | null, 45 | { 46 | "string": "hello" 47 | } 48 | ] 49 | } 50 | ] 51 | }`, 52 | OutDataJSON: `{ 53 | "F": [ 54 | { 55 | "int": 1 56 | }, 57 | { 58 | "array": [ 59 | null, 60 | { 61 | "string": "hello" 62 | } 63 | ] 64 | } 65 | ] 66 | }`, 67 | }}, 68 | } 69 | 70 | func TestGeneratedCode(t *testing.T) { 71 | tests.Test(t) 72 | } 73 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/nestedUnion/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "F", 7 | "type": { 8 | "type": "array", 9 | "items": [ 10 | "int", 11 | { 12 | "type": "array", 13 | "items": [ 14 | "null", 15 | "string" 16 | ] 17 | } 18 | ] 19 | } 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/nestedUnion/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package nestedUnion 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | // Allowed types for interface{} value: 11 | // int 12 | // []*string 13 | F []interface{} 14 | } 15 | 16 | // AvroRecord implements the avro.AvroRecord interface. 17 | func (R) AvroRecord() avrotypegen.RecordInfo { 18 | return avrotypegen.RecordInfo{ 19 | Schema: `{"fields":[{"name":"F","type":{"items":["int",{"items":["null","string"],"type":"array"}],"type":"array"}}],"name":"R","type":"record"}`, 20 | Required: []bool{ 21 | 0: true, 22 | }, 23 | Unions: []avrotypegen.UnionInfo{ 24 | 0: { 25 | Type: new([]interface{}), 26 | Union: []avrotypegen.UnionInfo{{ 27 | Type: new(int), 28 | }, { 29 | Type: new([]*string), 30 | Union: []avrotypegen.UnionInfo{{ 31 | Type: nil, 32 | }, { 33 | Type: new(string), 34 | }}, 35 | }}, 36 | }, 37 | }, 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/nestedUnionNestedArray/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package nestedUnionNestedArray 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "F", 18 | "type": { 19 | "type": "array", 20 | "items": { 21 | "type": "array", 22 | "items": [ 23 | "null", 24 | "string" 25 | ] 26 | } 27 | } 28 | } 29 | ] 30 | }`, 31 | GoType: new(R), 32 | Subtests: []testutil.RoundTripSubtest{{ 33 | TestName: "main", 34 | InDataJSON: `{ 35 | "F": [ 36 | [ 37 | null, 38 | { 39 | "string": "hello" 40 | } 41 | ], 42 | [ 43 | { 44 | "string": "goodbye" 45 | } 46 | ] 47 | ] 48 | }`, 49 | OutDataJSON: `{ 50 | "F": [ 51 | [ 52 | null, 53 | { 54 | "string": "hello" 55 | } 56 | ], 57 | [ 58 | { 59 | "string": "goodbye" 60 | } 61 | ] 62 | ] 63 | }`, 64 | }}, 65 | } 66 | 67 | func TestGeneratedCode(t *testing.T) { 68 | tests.Test(t) 69 | } 70 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/nestedUnionNestedArray/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "F", 7 | "type": { 8 | "type": "array", 9 | "items": { 10 | "type": "array", 11 | "items": [ 12 | "null", 13 | "string" 14 | ] 15 | } 16 | } 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/nestedUnionNestedArray/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package nestedUnionNestedArray 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | F [][]*string 11 | } 12 | 13 | // AvroRecord implements the avro.AvroRecord interface. 14 | func (R) AvroRecord() avrotypegen.RecordInfo { 15 | return avrotypegen.RecordInfo{ 16 | Schema: `{"fields":[{"name":"F","type":{"items":{"items":["null","string"],"type":"array"},"type":"array"}}],"name":"R","type":"record"}`, 17 | Required: []bool{ 18 | 0: true, 19 | }, 20 | Unions: []avrotypegen.UnionInfo{ 21 | 0: { 22 | Type: new([][]*string), 23 | Union: []avrotypegen.UnionInfo{{ 24 | Type: nil, 25 | }, { 26 | Type: new(string), 27 | }}, 28 | }, 29 | }, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/primitive/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "intField", 7 | "type": "int" 8 | }, 9 | { 10 | "name": "longField", 11 | "type": "long" 12 | }, 13 | { 14 | "name": "floatField", 15 | "type": "float" 16 | }, 17 | { 18 | "name": "doubleField", 19 | "type": "double" 20 | }, 21 | { 22 | "name": "boolField", 23 | "type": "boolean" 24 | }, 25 | { 26 | "name": "bytesField", 27 | "type": "bytes" 28 | }, 29 | { 30 | "name": "stringField", 31 | "type": "string" 32 | }, 33 | { 34 | "name": "nullField", 35 | "type": "null" 36 | } 37 | ] 38 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/primitive/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package primitive 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | IntField int `json:"intField"` 11 | LongField int64 `json:"longField"` 12 | FloatField float32 `json:"floatField"` 13 | DoubleField float64 `json:"doubleField"` 14 | BoolField bool `json:"boolField"` 15 | BytesField []byte `json:"bytesField"` 16 | StringField string `json:"stringField"` 17 | NullField avrotypegen.Null `json:"nullField"` 18 | } 19 | 20 | // AvroRecord implements the avro.AvroRecord interface. 21 | func (R) AvroRecord() avrotypegen.RecordInfo { 22 | return avrotypegen.RecordInfo{ 23 | Schema: `{"fields":[{"name":"intField","type":"int"},{"name":"longField","type":"long"},{"name":"floatField","type":"float"},{"name":"doubleField","type":"double"},{"name":"boolField","type":"boolean"},{"name":"bytesField","type":"bytes"},{"name":"stringField","type":"string"},{"name":"nullField","type":"null"}],"name":"R","type":"record"}`, 24 | Required: []bool{ 25 | 0: true, 26 | 1: true, 27 | 2: true, 28 | 3: true, 29 | 4: true, 30 | 5: true, 31 | 6: true, 32 | 7: true, 33 | }, 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/primitiveDefaults/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package primitiveDefaults 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "_", 18 | "type": "int", 19 | "default": 0 20 | } 21 | ] 22 | }`, 23 | GoType: new(R), 24 | Subtests: []testutil.RoundTripSubtest{{ 25 | TestName: "main", 26 | InDataJSON: `{ 27 | "_": 0 28 | }`, 29 | OutDataJSON: `{ 30 | "string": "hello", 31 | "int": 1111, 32 | "long": 2222, 33 | "float": 1.5, 34 | "double": 2.75, 35 | "boolean": true 36 | }`, 37 | }}, 38 | } 39 | 40 | func TestGeneratedCode(t *testing.T) { 41 | tests.Test(t) 42 | } 43 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/primitiveDefaults/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "int", 7 | "type": "int", 8 | "default": 1111 9 | }, 10 | { 11 | "name": "long", 12 | "type": "long", 13 | "default": 2222 14 | }, 15 | { 16 | "name": "string", 17 | "type": "string", 18 | "default": "hello" 19 | }, 20 | { 21 | "name": "float", 22 | "type": "float", 23 | "default": 1.5 24 | }, 25 | { 26 | "name": "double", 27 | "type": "double", 28 | "default": 2.75 29 | }, 30 | { 31 | "name": "boolean", 32 | "type": "boolean", 33 | "default": true 34 | } 35 | ] 36 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/primitiveDefaults/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package primitiveDefaults 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | Int int `json:"int"` 11 | Long int64 `json:"long"` 12 | String string `json:"string"` 13 | Float float32 `json:"float"` 14 | Double float64 `json:"double"` 15 | Boolean bool `json:"boolean"` 16 | } 17 | 18 | // AvroRecord implements the avro.AvroRecord interface. 19 | func (R) AvroRecord() avrotypegen.RecordInfo { 20 | return avrotypegen.RecordInfo{ 21 | Schema: `{"fields":[{"default":1111,"name":"int","type":"int"},{"default":2222,"name":"long","type":"long"},{"default":"hello","name":"string","type":"string"},{"default":1.5,"name":"float","type":"float"},{"default":2.75,"name":"double","type":"double"},{"default":true,"name":"boolean","type":"boolean"}],"name":"R","type":"record"}`, 22 | Defaults: []func() interface{}{ 23 | 0: func() interface{} { 24 | return 1111 25 | }, 26 | 1: func() interface{} { 27 | return int64(2222) 28 | }, 29 | 2: func() interface{} { 30 | return "hello" 31 | }, 32 | 3: func() interface{} { 33 | return float32(1.5) 34 | }, 35 | 4: func() interface{} { 36 | return 2.75 37 | }, 38 | 5: func() interface{} { 39 | return true 40 | }, 41 | }, 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/primitiveIncompatible/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package primitiveIncompatible 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "f", 18 | "type": "int" 19 | } 20 | ] 21 | }`, 22 | GoType: new(R), 23 | Subtests: []testutil.RoundTripSubtest{{ 24 | TestName: "main", 25 | InDataJSON: `{ 26 | "f": 2134 27 | }`, 28 | OutDataJSON: `null`, 29 | ExpectError: map[testutil.ErrorType]string{`unmarshal`: `cannot create decoder: Incompatible schemas: field f in reader has incompatible type in writer`}, 30 | }}, 31 | } 32 | 33 | func TestGeneratedCode(t *testing.T) { 34 | tests.Test(t) 35 | } 36 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/primitiveIncompatible/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "f", 7 | "type": "string" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/primitiveIncompatible/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package primitiveIncompatible 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | F string `json:"f"` 11 | } 12 | 13 | // AvroRecord implements the avro.AvroRecord interface. 14 | func (R) AvroRecord() avrotypegen.RecordInfo { 15 | return avrotypegen.RecordInfo{ 16 | Schema: `{"fields":[{"name":"f","type":"string"}],"name":"R","type":"record"}`, 17 | Required: []bool{ 18 | 0: true, 19 | }, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/recordDefault/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package recordDefault 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "_", 18 | "type": "int", 19 | "default": 0 20 | } 21 | ] 22 | }`, 23 | GoType: new(R), 24 | Subtests: []testutil.RoundTripSubtest{{ 25 | TestName: "main", 26 | InDataJSON: `{ 27 | "_": 0 28 | }`, 29 | OutDataJSON: `{ 30 | "recordField": { 31 | "F1": 44, 32 | "F2": "whee", 33 | "F3": "ok" 34 | } 35 | }`, 36 | }}, 37 | } 38 | 39 | func TestGeneratedCode(t *testing.T) { 40 | tests.Test(t) 41 | } 42 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/recordDefault/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "recordField", 7 | "type": { 8 | "name": "Foo", 9 | "type": "record", 10 | "fields": [ 11 | { 12 | "name": "F1", 13 | "type": "int" 14 | }, 15 | { 16 | "name": "F2", 17 | "type": "string" 18 | }, 19 | { 20 | "name": "F3", 21 | "type": "string", 22 | "default": "hello" 23 | } 24 | ] 25 | }, 26 | "default": { 27 | "F1": 44, 28 | "F2": "whee", 29 | "F3": "ok" 30 | } 31 | } 32 | ] 33 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/recordDefault/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package recordDefault 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type Foo struct { 10 | F1 int 11 | F2 string 12 | F3 string 13 | } 14 | 15 | // AvroRecord implements the avro.AvroRecord interface. 16 | func (Foo) AvroRecord() avrotypegen.RecordInfo { 17 | return avrotypegen.RecordInfo{ 18 | Schema: `{"fields":[{"name":"F1","type":"int"},{"name":"F2","type":"string"},{"default":"hello","name":"F3","type":"string"}],"name":"Foo","type":"record"}`, 19 | Required: []bool{ 20 | 0: true, 21 | 1: true, 22 | }, 23 | Defaults: []func() interface{}{ 24 | 2: func() interface{} { 25 | return "hello" 26 | }, 27 | }, 28 | } 29 | } 30 | 31 | type R struct { 32 | RecordField Foo `json:"recordField"` 33 | } 34 | 35 | // AvroRecord implements the avro.AvroRecord interface. 36 | func (R) AvroRecord() avrotypegen.RecordInfo { 37 | return avrotypegen.RecordInfo{ 38 | Schema: `{"fields":[{"default":{"F1":44,"F2":"whee","F3":"ok"},"name":"recordField","type":{"fields":[{"name":"F1","type":"int"},{"name":"F2","type":"string"},{"default":"hello","name":"F3","type":"string"}],"name":"Foo","type":"record"}}],"name":"R","type":"record"}`, 39 | Defaults: []func() interface{}{ 40 | 0: func() interface{} { 41 | return Foo{ 42 | F1: 44, 43 | F2: "whee", 44 | F3: "ok", 45 | } 46 | }, 47 | }, 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/sharedUnion/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package sharedUnion 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "A", 18 | "type": [ 19 | "int", 20 | "string", 21 | "float" 22 | ] 23 | }, 24 | { 25 | "name": "B", 26 | "type": [ 27 | "int", 28 | "string", 29 | "float" 30 | ] 31 | } 32 | ] 33 | }`, 34 | GoType: new(R), 35 | Subtests: []testutil.RoundTripSubtest{{ 36 | TestName: "main", 37 | InDataJSON: `{ 38 | "A": { 39 | "int": 244 40 | }, 41 | "B": { 42 | "string": "hello" 43 | } 44 | }`, 45 | OutDataJSON: `{ 46 | "A": { 47 | "int": 244 48 | }, 49 | "B": { 50 | "string": "hello" 51 | } 52 | }`, 53 | }}, 54 | } 55 | 56 | func TestGeneratedCode(t *testing.T) { 57 | tests.Test(t) 58 | } 59 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/sharedUnion/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "A", 7 | "type": [ 8 | "int", 9 | "string", 10 | "float" 11 | ] 12 | }, 13 | { 14 | "name": "B", 15 | "type": [ 16 | "int", 17 | "string", 18 | "float" 19 | ] 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/sharedUnion/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package sharedUnion 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | // Allowed types for interface{} value: 11 | // int 12 | // string 13 | // float32 14 | A interface{} 15 | 16 | // Allowed types for interface{} value: 17 | // int 18 | // string 19 | // float32 20 | B interface{} 21 | } 22 | 23 | // AvroRecord implements the avro.AvroRecord interface. 24 | func (R) AvroRecord() avrotypegen.RecordInfo { 25 | return avrotypegen.RecordInfo{ 26 | Schema: `{"fields":[{"name":"A","type":["int","string","float"]},{"name":"B","type":["int","string","float"]}],"name":"R","type":"record"}`, 27 | Required: []bool{ 28 | 0: true, 29 | 1: true, 30 | }, 31 | Unions: []avrotypegen.UnionInfo{ 32 | 0: { 33 | Type: new(interface{}), 34 | Union: []avrotypegen.UnionInfo{{ 35 | Type: new(int), 36 | }, { 37 | Type: new(string), 38 | }, { 39 | Type: new(float32), 40 | }}, 41 | }, 42 | 1: { 43 | Type: new(interface{}), 44 | Union: []avrotypegen.UnionInfo{{ 45 | Type: new(int), 46 | }, { 47 | Type: new(string), 48 | }, { 49 | Type: new(float32), 50 | }}, 51 | }, 52 | }, 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/simpleArray/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package simpleArray 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "A", 18 | "type": { 19 | "type": "array", 20 | "items": "int" 21 | } 22 | } 23 | ] 24 | }`, 25 | GoType: new(R), 26 | Subtests: []testutil.RoundTripSubtest{{ 27 | TestName: "empty", 28 | InDataJSON: `{ 29 | "A": [] 30 | }`, 31 | OutDataJSON: `{ 32 | "A": [] 33 | }`, 34 | }, { 35 | TestName: "non_empty", 36 | InDataJSON: `{ 37 | "A": [ 38 | 23, 39 | 57, 40 | 444 41 | ] 42 | }`, 43 | OutDataJSON: `{ 44 | "A": [ 45 | 23, 46 | 57, 47 | 444 48 | ] 49 | }`, 50 | }}, 51 | } 52 | 53 | func TestGeneratedCode(t *testing.T) { 54 | tests.Test(t) 55 | } 56 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/simpleArray/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "A", 7 | "type": { 8 | "type": "array", 9 | "items": "int" 10 | } 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/simpleArray/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package simpleArray 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | A []int 11 | } 12 | 13 | // AvroRecord implements the avro.AvroRecord interface. 14 | func (R) AvroRecord() avrotypegen.RecordInfo { 15 | return avrotypegen.RecordInfo{ 16 | Schema: `{"fields":[{"name":"A","type":{"items":"int","type":"array"}}],"name":"R","type":"record"}`, 17 | Required: []bool{ 18 | 0: true, 19 | }, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/simpleEnum/other_test.go: -------------------------------------------------------------------------------- 1 | package simpleEnum 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | 7 | qt "github.com/frankban/quicktest" 8 | 9 | "github.com/heetch/avro" 10 | ) 11 | 12 | func TestString(t *testing.T) { 13 | c := qt.New(t) 14 | c.Assert(MyEnumA.String(), qt.Equals, "a") 15 | c.Assert(MyEnumB.String(), qt.Equals, "b") 16 | c.Assert(MyEnumC.String(), qt.Equals, "c") 17 | c.Assert(MyEnum(-1).String(), qt.Equals, "MyEnum(-1)") 18 | c.Assert(MyEnum(3).String(), qt.Equals, "MyEnum(3)") 19 | } 20 | 21 | func TestMarshalText(t *testing.T) { 22 | c := qt.New(t) 23 | data, err := MyEnumA.MarshalText() 24 | c.Assert(err, qt.Equals, nil) 25 | c.Assert(string(data), qt.Equals, "a") 26 | 27 | _, err = MyEnum(-1).MarshalText() 28 | c.Assert(err, qt.ErrorMatches, `MyEnum value -1 is out of bounds`) 29 | 30 | _, err = MyEnum(3).MarshalText() 31 | c.Assert(err, qt.ErrorMatches, `MyEnum value 3 is out of bounds`) 32 | } 33 | 34 | func TestUnmarshalText(t *testing.T) { 35 | c := qt.New(t) 36 | var e MyEnum 37 | err := e.UnmarshalText([]byte("b")) 38 | c.Assert(err, qt.Equals, nil) 39 | c.Assert(e, qt.Equals, MyEnumB) 40 | 41 | // Check that it works OK with encoding/json too. 42 | var x struct { 43 | E MyEnum 44 | } 45 | err = json.Unmarshal([]byte(`{"E": "c"}`), &x) 46 | c.Assert(err, qt.Equals, nil) 47 | c.Assert(x.E, qt.Equals, MyEnumC) 48 | 49 | x.E = 0 50 | err = json.Unmarshal([]byte(`{"E": "unknown"}`), &x) 51 | c.Assert(err, qt.ErrorMatches, `unknown value "unknown" for MyEnum`) 52 | } 53 | 54 | func TestSchema(t *testing.T) { 55 | c := qt.New(t) 56 | at, err := avro.TypeOf(MyEnumA) 57 | c.Assert(err, qt.Equals, nil) 58 | c.Assert(at.String(), qt.JSONEquals, json.RawMessage(`{ 59 | "type": "enum", 60 | "name": "MyEnum", 61 | "symbols": ["a", "b", "c"] 62 | }`)) 63 | } 64 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/simpleEnum/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package simpleEnum 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "E", 18 | "type": { 19 | "name": "MyEnum", 20 | "type": "enum", 21 | "symbols": [ 22 | "a", 23 | "b", 24 | "c" 25 | ] 26 | } 27 | } 28 | ] 29 | }`, 30 | GoType: new(R), 31 | Subtests: []testutil.RoundTripSubtest{{ 32 | TestName: "main", 33 | InDataJSON: `{ 34 | "E": "b" 35 | }`, 36 | OutDataJSON: `{ 37 | "E": "b" 38 | }`, 39 | }}, 40 | } 41 | 42 | func TestGeneratedCode(t *testing.T) { 43 | tests.Test(t) 44 | } 45 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/simpleEnum/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "E", 7 | "type": { 8 | "name": "MyEnum", 9 | "type": "enum", 10 | "symbols": [ 11 | "a", 12 | "b", 13 | "c" 14 | ] 15 | } 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/simpleEnum/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package simpleEnum 4 | 5 | import ( 6 | "fmt" 7 | "github.com/heetch/avro/avrotypegen" 8 | "strconv" 9 | ) 10 | 11 | type MyEnum int 12 | 13 | const ( 14 | MyEnumA MyEnum = iota 15 | MyEnumB 16 | MyEnumC 17 | ) 18 | 19 | var _MyEnum_strings = []string{ 20 | "a", 21 | "b", 22 | "c", 23 | } 24 | 25 | // String returns the textual representation of MyEnum. 26 | func (e MyEnum) String() string { 27 | if e < 0 || int(e) >= len(_MyEnum_strings) { 28 | return "MyEnum(" + strconv.FormatInt(int64(e), 10) + ")" 29 | } 30 | return _MyEnum_strings[e] 31 | } 32 | 33 | // MarshalText implements encoding.TextMarshaler 34 | // by returning the textual representation of MyEnum. 35 | func (e MyEnum) MarshalText() ([]byte, error) { 36 | if e < 0 || int(e) >= len(_MyEnum_strings) { 37 | return nil, fmt.Errorf("MyEnum value %d is out of bounds", e) 38 | } 39 | return []byte(_MyEnum_strings[e]), nil 40 | } 41 | 42 | // UnmarshalText implements encoding.TextUnmarshaler 43 | // by expecting the textual representation of MyEnum. 44 | func (e *MyEnum) UnmarshalText(data []byte) error { 45 | // Note for future: this could be more efficient. 46 | for i, s := range _MyEnum_strings { 47 | if string(data) == s { 48 | *e = MyEnum(i) 49 | return nil 50 | } 51 | } 52 | return fmt.Errorf("unknown value %q for MyEnum", data) 53 | } 54 | 55 | type R struct { 56 | E MyEnum 57 | } 58 | 59 | // AvroRecord implements the avro.AvroRecord interface. 60 | func (R) AvroRecord() avrotypegen.RecordInfo { 61 | return avrotypegen.RecordInfo{ 62 | Schema: `{"fields":[{"name":"E","type":{"name":"MyEnum","symbols":["a","b","c"],"type":"enum"}}],"name":"R","type":"record"}`, 63 | Required: []bool{ 64 | 0: true, 65 | }, 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/simpleFixed/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package simpleFixed 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "F", 18 | "type": { 19 | "name": "five", 20 | "type": "fixed", 21 | "size": 5 22 | } 23 | } 24 | ] 25 | }`, 26 | GoType: new(R), 27 | Subtests: []testutil.RoundTripSubtest{{ 28 | TestName: "main", 29 | InDataJSON: `{ 30 | "F": "abcde" 31 | }`, 32 | OutDataJSON: `{ 33 | "F": "abcde" 34 | }`, 35 | }}, 36 | } 37 | 38 | func TestGeneratedCode(t *testing.T) { 39 | tests.Test(t) 40 | } 41 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/simpleFixed/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "F", 7 | "type": { 8 | "name": "five", 9 | "type": "fixed", 10 | "size": 5 11 | } 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/simpleFixed/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package simpleFixed 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | F Five 11 | } 12 | 13 | // AvroRecord implements the avro.AvroRecord interface. 14 | func (R) AvroRecord() avrotypegen.RecordInfo { 15 | return avrotypegen.RecordInfo{ 16 | Schema: `{"fields":[{"name":"F","type":{"name":"five","size":5,"type":"fixed"}}],"name":"R","type":"record"}`, 17 | Required: []bool{ 18 | 0: true, 19 | }, 20 | } 21 | } 22 | 23 | type Five [5]byte 24 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/simpleInUnionOut/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package simpleInUnionOut 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "UnionField", 18 | "type": "string" 19 | } 20 | ] 21 | }`, 22 | GoType: new(R), 23 | Subtests: []testutil.RoundTripSubtest{{ 24 | TestName: "main", 25 | InDataJSON: `{ 26 | "UnionField": "hello" 27 | }`, 28 | OutDataJSON: `{ 29 | "UnionField": { 30 | "string": "hello" 31 | } 32 | }`, 33 | }}, 34 | } 35 | 36 | func TestGeneratedCode(t *testing.T) { 37 | tests.Test(t) 38 | } 39 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/simpleInUnionOut/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "UnionField", 7 | "type": [ 8 | "int", 9 | "long", 10 | "float", 11 | "double", 12 | "string", 13 | "boolean", 14 | "null" 15 | ], 16 | "default": 1234 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/simpleInUnionOut/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package simpleInUnionOut 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | // Allowed types for interface{} value: 11 | // int 12 | // int64 13 | // float32 14 | // float64 15 | // string 16 | // bool 17 | // avrotypegen.Null 18 | UnionField interface{} 19 | } 20 | 21 | // AvroRecord implements the avro.AvroRecord interface. 22 | func (R) AvroRecord() avrotypegen.RecordInfo { 23 | return avrotypegen.RecordInfo{ 24 | Schema: `{"fields":[{"default":1234,"name":"UnionField","type":["int","long","float","double","string","boolean","null"]}],"name":"R","type":"record"}`, 25 | Defaults: []func() interface{}{ 26 | 0: func() interface{} { 27 | return 1234 28 | }, 29 | }, 30 | Unions: []avrotypegen.UnionInfo{ 31 | 0: { 32 | Type: new(interface{}), 33 | Union: []avrotypegen.UnionInfo{{ 34 | Type: new(int), 35 | }, { 36 | Type: new(int64), 37 | }, { 38 | Type: new(float32), 39 | }, { 40 | Type: new(float64), 41 | }, { 42 | Type: new(string), 43 | }, { 44 | Type: new(bool), 45 | }, { 46 | Type: nil, 47 | }}, 48 | }, 49 | }, 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/simpleMap/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package simpleMap 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "M", 18 | "type": { 19 | "type": "map", 20 | "values": "int" 21 | } 22 | } 23 | ] 24 | }`, 25 | GoType: new(R), 26 | Subtests: []testutil.RoundTripSubtest{{ 27 | TestName: "empty", 28 | InDataJSON: `{ 29 | "M": {} 30 | }`, 31 | OutDataJSON: `{ 32 | "M": {} 33 | }`, 34 | }, { 35 | TestName: "non_empty", 36 | InDataJSON: `{ 37 | "M": { 38 | "a": 32, 39 | "b": 54 40 | } 41 | }`, 42 | OutDataJSON: `{ 43 | "M": { 44 | "a": 32, 45 | "b": 54 46 | } 47 | }`, 48 | }}, 49 | } 50 | 51 | func TestGeneratedCode(t *testing.T) { 52 | tests.Test(t) 53 | } 54 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/simpleMap/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "M", 7 | "type": { 8 | "type": "map", 9 | "values": "int" 10 | } 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/simpleMap/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package simpleMap 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | M map[string]int 11 | } 12 | 13 | // AvroRecord implements the avro.AvroRecord interface. 14 | func (R) AvroRecord() avrotypegen.RecordInfo { 15 | return avrotypegen.RecordInfo{ 16 | Schema: `{"fields":[{"name":"M","type":{"type":"map","values":"int"}}],"name":"R","type":"record"}`, 17 | Required: []bool{ 18 | 0: true, 19 | }, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/timestampMicros/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package timestampMicros 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "T", 18 | "type": { 19 | "type": "long", 20 | "logicalType": "timestamp-micros" 21 | } 22 | } 23 | ] 24 | }`, 25 | GoType: new(R), 26 | Subtests: []testutil.RoundTripSubtest{{ 27 | TestName: "main", 28 | InDataJSON: `{ 29 | "T": 1579176162000001 30 | }`, 31 | OutDataJSON: `{ 32 | "T": 1579176162000001 33 | }`, 34 | }}, 35 | } 36 | 37 | func TestGeneratedCode(t *testing.T) { 38 | tests.Test(t) 39 | } 40 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/timestampMicros/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "T", 7 | "type": { 8 | "type": "long", 9 | "logicalType": "timestamp-micros" 10 | } 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/timestampMicros/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package timestampMicros 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | "time" 8 | ) 9 | 10 | type R struct { 11 | T time.Time 12 | } 13 | 14 | // AvroRecord implements the avro.AvroRecord interface. 15 | func (R) AvroRecord() avrotypegen.RecordInfo { 16 | return avrotypegen.RecordInfo{ 17 | Schema: `{"fields":[{"name":"T","type":{"logicalType":"timestamp-micros","type":"long"}}],"name":"R","type":"record"}`, 18 | Required: []bool{ 19 | 0: true, 20 | }, 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionInOut/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package unionInOut 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "PrimitiveUnionTestRecord", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "UnionField", 18 | "type": [ 19 | "int", 20 | "long", 21 | "float", 22 | "double", 23 | "string", 24 | "boolean", 25 | "null" 26 | ], 27 | "default": 1234 28 | } 29 | ] 30 | }`, 31 | GoType: new(PrimitiveUnionTestRecord), 32 | Subtests: []testutil.RoundTripSubtest{{ 33 | TestName: "withBoolean", 34 | InDataJSON: `{ 35 | "UnionField": { 36 | "boolean": true 37 | } 38 | }`, 39 | OutDataJSON: `{ 40 | "UnionField": { 41 | "boolean": true 42 | } 43 | }`, 44 | }, { 45 | TestName: "withInt", 46 | InDataJSON: `{ 47 | "UnionField": { 48 | "int": 999 49 | } 50 | }`, 51 | OutDataJSON: `{ 52 | "UnionField": { 53 | "int": 999 54 | } 55 | }`, 56 | }, { 57 | TestName: "withNull", 58 | InDataJSON: `{ 59 | "UnionField": null 60 | }`, 61 | OutDataJSON: `{ 62 | "UnionField": null 63 | }`, 64 | }}, 65 | } 66 | 67 | func TestGeneratedCode(t *testing.T) { 68 | tests.Test(t) 69 | } 70 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionInOut/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PrimitiveUnionTestRecord", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "UnionField", 7 | "type": [ 8 | "int", 9 | "long", 10 | "float", 11 | "double", 12 | "string", 13 | "boolean", 14 | "null" 15 | ], 16 | "default": 1234 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionInOut/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package unionInOut 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type PrimitiveUnionTestRecord struct { 10 | // Allowed types for interface{} value: 11 | // int 12 | // int64 13 | // float32 14 | // float64 15 | // string 16 | // bool 17 | // avrotypegen.Null 18 | UnionField interface{} 19 | } 20 | 21 | // AvroRecord implements the avro.AvroRecord interface. 22 | func (PrimitiveUnionTestRecord) AvroRecord() avrotypegen.RecordInfo { 23 | return avrotypegen.RecordInfo{ 24 | Schema: `{"fields":[{"default":1234,"name":"UnionField","type":["int","long","float","double","string","boolean","null"]}],"name":"PrimitiveUnionTestRecord","type":"record"}`, 25 | Defaults: []func() interface{}{ 26 | 0: func() interface{} { 27 | return 1234 28 | }, 29 | }, 30 | Unions: []avrotypegen.UnionInfo{ 31 | 0: { 32 | Type: new(interface{}), 33 | Union: []avrotypegen.UnionInfo{{ 34 | Type: new(int), 35 | }, { 36 | Type: new(int64), 37 | }, { 38 | Type: new(float32), 39 | }, { 40 | Type: new(float64), 41 | }, { 42 | Type: new(string), 43 | }, { 44 | Type: new(bool), 45 | }, { 46 | Type: nil, 47 | }}, 48 | }, 49 | }, 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionInSimpleOut/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package unionInSimpleOut 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "UnionField", 18 | "type": [ 19 | "int", 20 | "long", 21 | "float", 22 | "double", 23 | "string", 24 | "boolean", 25 | "null" 26 | ], 27 | "default": 1234 28 | } 29 | ] 30 | }`, 31 | GoType: new(R), 32 | Subtests: []testutil.RoundTripSubtest{{ 33 | TestName: "main", 34 | InDataJSON: `{ 35 | "UnionField": { 36 | "string": "hello" 37 | } 38 | }`, 39 | OutDataJSON: `{ 40 | "UnionField": "hello" 41 | }`, 42 | }}, 43 | } 44 | 45 | func TestGeneratedCode(t *testing.T) { 46 | tests.Test(t) 47 | } 48 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionInSimpleOut/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "UnionField", 7 | "type": "string" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionInSimpleOut/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package unionInSimpleOut 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | UnionField string 11 | } 12 | 13 | // AvroRecord implements the avro.AvroRecord interface. 14 | func (R) AvroRecord() avrotypegen.RecordInfo { 15 | return avrotypegen.RecordInfo{ 16 | Schema: `{"fields":[{"name":"UnionField","type":"string"}],"name":"R","type":"record"}`, 17 | Required: []bool{ 18 | 0: true, 19 | }, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionIntVsLong/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package unionIntVsLong 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "F", 18 | "type": [ 19 | "int", 20 | "string" 21 | ], 22 | "default": 1234 23 | } 24 | ] 25 | }`, 26 | GoType: new(R), 27 | Subtests: []testutil.RoundTripSubtest{{ 28 | TestName: "main", 29 | InDataJSON: `{ 30 | "F": { 31 | "int": 999 32 | } 33 | }`, 34 | OutDataJSON: `{ 35 | "F": { 36 | "int": 999 37 | } 38 | }`, 39 | }}, 40 | } 41 | 42 | func TestGeneratedCode(t *testing.T) { 43 | tests.Test(t) 44 | } 45 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionIntVsLong/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "F", 7 | "type": [ 8 | "long", 9 | "int", 10 | "string" 11 | ], 12 | "default": 1234 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionIntVsLong/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package unionIntVsLong 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | // Allowed types for interface{} value: 11 | // int64 12 | // int 13 | // string 14 | F interface{} 15 | } 16 | 17 | // AvroRecord implements the avro.AvroRecord interface. 18 | func (R) AvroRecord() avrotypegen.RecordInfo { 19 | return avrotypegen.RecordInfo{ 20 | Schema: `{"fields":[{"default":1234,"name":"F","type":["long","int","string"]}],"name":"R","type":"record"}`, 21 | Defaults: []func() interface{}{ 22 | 0: func() interface{} { 23 | return int64(1234) 24 | }, 25 | }, 26 | Unions: []avrotypegen.UnionInfo{ 27 | 0: { 28 | Type: new(interface{}), 29 | Union: []avrotypegen.UnionInfo{{ 30 | Type: new(int64), 31 | }, { 32 | Type: new(int), 33 | }, { 34 | Type: new(string), 35 | }}, 36 | }, 37 | }, 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionNullString/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package unionNullString 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "OptionalString", 18 | "type": [ 19 | "null", 20 | "string" 21 | ] 22 | } 23 | ] 24 | }`, 25 | GoType: new(R), 26 | Subtests: []testutil.RoundTripSubtest{{ 27 | TestName: "withNull", 28 | InDataJSON: `{ 29 | "OptionalString": null 30 | }`, 31 | OutDataJSON: `{ 32 | "OptionalString": null 33 | }`, 34 | }, { 35 | TestName: "withString", 36 | InDataJSON: `{ 37 | "OptionalString": { 38 | "string": "hello" 39 | } 40 | }`, 41 | OutDataJSON: `{ 42 | "OptionalString": { 43 | "string": "hello" 44 | } 45 | }`, 46 | }}, 47 | } 48 | 49 | func TestGeneratedCode(t *testing.T) { 50 | tests.Test(t) 51 | } 52 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionNullString/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "OptionalString", 7 | "type": [ 8 | "null", 9 | "string" 10 | ] 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionNullString/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package unionNullString 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | OptionalString *string 11 | } 12 | 13 | // AvroRecord implements the avro.AvroRecord interface. 14 | func (R) AvroRecord() avrotypegen.RecordInfo { 15 | return avrotypegen.RecordInfo{ 16 | Schema: `{"fields":[{"name":"OptionalString","type":["null","string"]}],"name":"R","type":"record"}`, 17 | Required: []bool{ 18 | 0: true, 19 | }, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionNullStringReverse/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package unionNullStringReverse 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "OptionalString", 18 | "type": [ 19 | "string", 20 | "null" 21 | ] 22 | } 23 | ] 24 | }`, 25 | GoType: new(R), 26 | Subtests: []testutil.RoundTripSubtest{{ 27 | TestName: "withNull", 28 | InDataJSON: `{ 29 | "OptionalString": null 30 | }`, 31 | OutDataJSON: `{ 32 | "OptionalString": null 33 | }`, 34 | }, { 35 | TestName: "withString", 36 | InDataJSON: `{ 37 | "OptionalString": { 38 | "string": "hello" 39 | } 40 | }`, 41 | OutDataJSON: `{ 42 | "OptionalString": { 43 | "string": "hello" 44 | } 45 | }`, 46 | }}, 47 | } 48 | 49 | func TestGeneratedCode(t *testing.T) { 50 | tests.Test(t) 51 | } 52 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionNullStringReverse/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "OptionalString", 7 | "type": [ 8 | "string", 9 | "null" 10 | ] 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionNullStringReverse/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package unionNullStringReverse 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type R struct { 10 | OptionalString *string 11 | } 12 | 13 | // AvroRecord implements the avro.AvroRecord interface. 14 | func (R) AvroRecord() avrotypegen.RecordInfo { 15 | return avrotypegen.RecordInfo{ 16 | Schema: `{"fields":[{"name":"OptionalString","type":["string","null"]}],"name":"R","type":"record"}`, 17 | Required: []bool{ 18 | 0: true, 19 | }, 20 | Unions: []avrotypegen.UnionInfo{ 21 | 0: { 22 | Type: new(*string), 23 | Union: []avrotypegen.UnionInfo{{ 24 | Type: new(string), 25 | }, { 26 | Type: nil, 27 | }}, 28 | }, 29 | }, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionToScalar/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package unionToScalar 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "PrimitiveUnionTestRecord", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "UnionField", 18 | "type": [ 19 | "int", 20 | "long", 21 | "float", 22 | "double", 23 | "string", 24 | "boolean", 25 | "null" 26 | ], 27 | "default": 1234 28 | } 29 | ] 30 | }`, 31 | GoType: new(PrimitiveUnionTestRecord), 32 | Subtests: []testutil.RoundTripSubtest{{ 33 | TestName: "main", 34 | InDataJSON: `{ 35 | "UnionField": { 36 | "int": 999 37 | } 38 | }`, 39 | OutDataJSON: `{ 40 | "UnionField": 999 41 | }`, 42 | }}, 43 | } 44 | 45 | func TestGeneratedCode(t *testing.T) { 46 | tests.Test(t) 47 | } 48 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionToScalar/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PrimitiveUnionTestRecord", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "UnionField", 7 | "type": "int", 8 | "default": 1234 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/unionToScalar/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package unionToScalar 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type PrimitiveUnionTestRecord struct { 10 | UnionField int 11 | } 12 | 13 | // AvroRecord implements the avro.AvroRecord interface. 14 | func (PrimitiveUnionTestRecord) AvroRecord() avrotypegen.RecordInfo { 15 | return avrotypegen.RecordInfo{ 16 | Schema: `{"fields":[{"default":1234,"name":"UnionField","type":"int"}],"name":"PrimitiveUnionTestRecord","type":"record"}`, 17 | Defaults: []func() interface{}{ 18 | 0: func() interface{} { 19 | return 1234 20 | }, 21 | }, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/uuid/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by generatetestcode.go; DO NOT EDIT. 2 | 3 | package uuid 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/heetch/avro/cmd/avrogo/internal/testutil" 9 | ) 10 | 11 | var tests = testutil.RoundTripTest{ 12 | InSchema: `{ 13 | "name": "R", 14 | "type": "record", 15 | "fields": [ 16 | { 17 | "name": "T", 18 | "type": { 19 | "type": "string", 20 | "logicalType": "uuid" 21 | } 22 | } 23 | ] 24 | }`, 25 | GoType: new(R), 26 | Subtests: []testutil.RoundTripSubtest{{ 27 | TestName: "main", 28 | InDataJSON: `{ 29 | "T": "6ba7b810-9dad-11d1-80b4-00c04fd430c8" 30 | }`, 31 | OutDataJSON: `{ 32 | "T": "6ba7b810-9dad-11d1-80b4-00c04fd430c8" 33 | }`, 34 | }}, 35 | } 36 | 37 | func TestGeneratedCode(t *testing.T) { 38 | tests.Test(t) 39 | } 40 | -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/uuid/schema.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "T", 7 | "type": { 8 | "type": "string", 9 | "logicalType": "uuid" 10 | } 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /cmd/avrogo/internal/generated_tests/uuid/schema_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package uuid 4 | 5 | import ( 6 | uuid "github.com/google/uuid" 7 | "github.com/heetch/avro/avrotypegen" 8 | ) 9 | 10 | type R struct { 11 | T uuid.UUID 12 | } 13 | 14 | // AvroRecord implements the avro.AvroRecord interface. 15 | func (R) AvroRecord() avrotypegen.RecordInfo { 16 | return avrotypegen.RecordInfo{ 17 | Schema: `{"fields":[{"name":"T","type":{"logicalType":"uuid","type":"string"}}],"name":"R","type":"record"}`, 18 | Required: []bool{ 19 | 0: true, 20 | }, 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /cmd/avrogo/outputpath_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | 6 | qt "github.com/frankban/quicktest" 7 | ) 8 | 9 | var outputPathsTests = []struct { 10 | testName string 11 | paths []string 12 | testFile bool 13 | expectError string 14 | expect map[string]string 15 | }{{ 16 | testName: "single-path", 17 | paths: []string{"foo.avsc"}, 18 | expect: map[string]string{ 19 | "foo.avsc": "foo_gen.go", 20 | }, 21 | }, { 22 | testName: "several-paths", 23 | paths: []string{"foo.avsc", "bar.avsc"}, 24 | expect: map[string]string{ 25 | "foo.avsc": "foo_gen.go", 26 | "bar.avsc": "bar_gen.go", 27 | }, 28 | }, { 29 | testName: "ambiguous-paths", 30 | paths: []string{"alpha/bravo/x.avsc", "alpha/charlie/x.avsc"}, 31 | expect: map[string]string{ 32 | "alpha/bravo/x.avsc": "bravo_x_gen.go", 33 | "alpha/charlie/x.avsc": "charlie_x_gen.go", 34 | }, 35 | }, { 36 | testName: "multiple-levels", 37 | paths: []string{"foo.avsc", "a/b/versions/v0.avsc", "a/c/versions/v0.avsc", "alpha/bravo/x.avsc", "alpha/charlie/x.avsc"}, 38 | expect: map[string]string{ 39 | "foo.avsc": "foo_gen.go", 40 | "a/b/versions/v0.avsc": "b_versions_v0_gen.go", 41 | "a/c/versions/v0.avsc": "c_versions_v0_gen.go", 42 | "alpha/bravo/x.avsc": "bravo_x_gen.go", 43 | "alpha/charlie/x.avsc": "charlie_x_gen.go", 44 | }, 45 | }, { 46 | testName: "ambiguous-until-root", 47 | paths: []string{"/foo/bar.avsc", "foo/bar.avsc"}, 48 | expect: map[string]string{ 49 | "/foo/bar.avsc": "slash_foo_bar_gen.go", 50 | "foo/bar.avsc": "foo_bar_gen.go", 51 | }, 52 | }, { 53 | testName: "ambiguous-until-start-of-relative", 54 | paths: []string{"foo/bar.avsc", "bar.avsc"}, 55 | expect: map[string]string{ 56 | "foo/bar.avsc": "foo_bar_gen.go", 57 | "bar.avsc": "bar_gen.go", 58 | }, 59 | }, { 60 | testName: "duplicate paths", 61 | paths: []string{"x.avsc", "x.avsc"}, 62 | expect: map[string]string{ 63 | "x.avsc": "x_gen.go", 64 | }, 65 | }, { 66 | testName: "ambiguous-underscores", 67 | paths: []string{"x/y.avsc", "x_y.avsc", "z/y.avsc"}, 68 | expectError: "could not make unambiguous output files from input files", 69 | }, { 70 | testName: "ambiguous-ext", 71 | paths: []string{"x.json", "x.avsc"}, 72 | expectError: "could not make unambiguous output files from input files", 73 | }} 74 | 75 | func TestOutputPaths(t *testing.T) { 76 | c := qt.New(t) 77 | for _, test := range outputPathsTests { 78 | c.Run(test.testName, func(c *qt.C) { 79 | result, err := outputPaths(test.paths, test.testFile) 80 | if test.expectError != "" { 81 | c.Check(result, qt.IsNil) 82 | c.Assert(err, qt.ErrorMatches, test.expectError) 83 | return 84 | } 85 | c.Assert(err, qt.IsNil) 86 | c.Assert(result, qt.DeepEquals, test.expect) 87 | }) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /cmd/avrogo/script_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/rogpeppe/go-internal/gotooltest" 8 | "github.com/rogpeppe/go-internal/testscript" 9 | ) 10 | 11 | func TestMain(m *testing.M) { 12 | os.Exit(testscript.RunMain(m, map[string]func() int{ 13 | "avrogo": main1, 14 | })) 15 | } 16 | 17 | func TestScript(t *testing.T) { 18 | p := testscript.Params{ 19 | Dir: "testdata/script", 20 | } 21 | if err := gotooltest.Setup(&p); err != nil { 22 | t.Fatal(err) 23 | } 24 | testscript.Run(t, p) 25 | } 26 | -------------------------------------------------------------------------------- /cmd/avrogo/testdata/array.cue: -------------------------------------------------------------------------------- 1 | package roundtrip 2 | 3 | tests: simpleArray: { 4 | inSchema: { 5 | type: "record" 6 | name: "R" 7 | fields: [{ 8 | name: "A" 9 | type: { 10 | type: "array" 11 | items: "int" 12 | } 13 | }] 14 | } 15 | outSchema: inSchema 16 | } 17 | 18 | tests: simpleArray: subtests: non_empty: { 19 | inData: A: [23, 57, 444] 20 | outData: inData 21 | } 22 | 23 | tests: simpleArray: subtests: empty: { 24 | inData: A: [] 25 | outData: inData 26 | } 27 | -------------------------------------------------------------------------------- /cmd/avrogo/testdata/cloudevent.cue: -------------------------------------------------------------------------------- 1 | package roundtrip 2 | 3 | tests: cloudEvent: { 4 | DomainName :: "someDomain" 5 | EventName :: "someEvent" 6 | Version :: "v9.9.99" 7 | inSchema: { 8 | type: "record" 9 | name: "com.heetch.\(DomainName).\(EventName)" 10 | heetchmeta: { 11 | commentary: "This Schema describes version \(Version) of the event \(EventName) from the domain \(DomainName)." 12 | topickey: "\(DomainName).\(EventName).\(Version)" 13 | } 14 | fields: [{ 15 | name: "Metadata" 16 | type: { 17 | type: "record" 18 | name: "Metadata" 19 | fields: [{ 20 | name: "CloudEvent" 21 | type: { 22 | type: "record" 23 | name: "CloudEvent" 24 | fields: [{ 25 | name: "id" 26 | type: "string" 27 | }, { 28 | doc: "* source holds the\n\t\t * source of the message." 29 | name: "source" 30 | type: "string" 31 | }, { 32 | name: "specversion" 33 | type: "string" 34 | }, { 35 | name: "time" 36 | type: { 37 | type: "long" 38 | logicalType: "timestamp-micros" 39 | } 40 | }] 41 | } 42 | }] 43 | } 44 | }, { 45 | name: "other" 46 | type: "string" 47 | }] 48 | } 49 | goType: "Message" 50 | outSchema: { 51 | type: "record" 52 | name: "com.heetch.Message" 53 | fields: [{ 54 | name: "Metadata" 55 | type: { 56 | type: "record" 57 | name: "Metadata" 58 | fields: [{ 59 | name: "CloudEvent" 60 | type: { 61 | type: "record" 62 | name: "CloudEvent" 63 | fields: [{ 64 | name: "id" 65 | type: "string" 66 | }, { 67 | doc: "* source holds the\n\t\t * source of the message." 68 | name: "source" 69 | type: "string" 70 | }, { 71 | name: "specversion" 72 | type: "string" 73 | }, { 74 | name: "time" 75 | type: { 76 | type: "long" 77 | logicalType: "timestamp-micros" 78 | } 79 | }] 80 | } 81 | }] 82 | } 83 | }] 84 | } 85 | inData: { 86 | Metadata: CloudEvent: { 87 | id: "id1" 88 | source: "source1" 89 | specversion: "someversion" 90 | time: 1580392724000000 91 | } 92 | other: "some other data" 93 | } 94 | outData: Metadata: inData.Metadata 95 | } 96 | -------------------------------------------------------------------------------- /cmd/avrogo/testdata/enum.cue: -------------------------------------------------------------------------------- 1 | package roundtrip 2 | 3 | tests: simpleEnum: { 4 | inSchema: { 5 | type: "record" 6 | name: "R" 7 | fields: [{ 8 | name: "E" 9 | type: { 10 | type: "enum" 11 | name: "MyEnum" 12 | symbols: ["a", "b", "c"] 13 | } 14 | }] 15 | } 16 | outSchema: inSchema 17 | inData: E: "b" 18 | outData: inData 19 | } 20 | 21 | tests: justEnum: { 22 | inSchema: { 23 | type: "enum" 24 | name: "MyEnum" 25 | symbols: ["a", "b", "c"] 26 | } 27 | outSchema: inSchema 28 | inData: "b" 29 | outData: inData 30 | } 31 | 32 | tests: simpleEnum: otherTests: """ 33 | package simpleEnum 34 | import ( 35 | "encoding/json" 36 | "testing" 37 | 38 | qt "github.com/frankban/quicktest" 39 | 40 | "github.com/heetch/avro" 41 | ) 42 | 43 | func TestString(t *testing.T) { 44 | c := qt.New(t) 45 | c.Assert(MyEnumA.String(), qt.Equals, "a") 46 | c.Assert(MyEnumB.String(), qt.Equals, "b") 47 | c.Assert(MyEnumC.String(), qt.Equals, "c") 48 | c.Assert(MyEnum(-1).String(), qt.Equals, "MyEnum(-1)") 49 | c.Assert(MyEnum(3).String(), qt.Equals, "MyEnum(3)") 50 | } 51 | 52 | func TestMarshalText(t *testing.T) { 53 | c := qt.New(t) 54 | data, err := MyEnumA.MarshalText() 55 | c.Assert(err, qt.Equals, nil) 56 | c.Assert(string(data), qt.Equals, "a") 57 | 58 | _, err = MyEnum(-1).MarshalText() 59 | c.Assert(err, qt.ErrorMatches, `MyEnum value -1 is out of bounds`) 60 | 61 | _, err = MyEnum(3).MarshalText() 62 | c.Assert(err, qt.ErrorMatches, `MyEnum value 3 is out of bounds`) 63 | } 64 | 65 | func TestUnmarshalText(t *testing.T) { 66 | c := qt.New(t) 67 | var e MyEnum 68 | err := e.UnmarshalText([]byte("b")) 69 | c.Assert(err, qt.Equals, nil) 70 | c.Assert(e, qt.Equals, MyEnumB) 71 | 72 | // Check that it works OK with encoding/json too. 73 | var x struct { 74 | E MyEnum 75 | } 76 | err = json.Unmarshal([]byte(`{"E": "c"}`), &x) 77 | c.Assert(err, qt.Equals, nil) 78 | c.Assert(x.E, qt.Equals, MyEnumC) 79 | 80 | x.E = 0 81 | err = json.Unmarshal([]byte(`{"E": "unknown"}`), &x) 82 | c.Assert(err, qt.ErrorMatches, `unknown value "unknown" for MyEnum`) 83 | } 84 | 85 | func TestSchema(t *testing.T) { 86 | c := qt.New(t) 87 | at, err := avro.TypeOf(MyEnumA) 88 | c.Assert(err, qt.Equals, nil) 89 | c.Assert(at.String(), qt.JSONEquals, json.RawMessage(`{ 90 | "type": "enum", 91 | "name": "MyEnum", 92 | "symbols": ["a", "b", "c"] 93 | }`)) 94 | } 95 | """ 96 | -------------------------------------------------------------------------------- /cmd/avrogo/testdata/fixed.cue: -------------------------------------------------------------------------------- 1 | package roundtrip 2 | 3 | tests: simpleFixed: { 4 | inSchema: { 5 | type: "record" 6 | name: "R" 7 | fields: [{ 8 | name: "F" 9 | type: { 10 | type: "fixed" 11 | size: 5 12 | name: "five" 13 | } 14 | }] 15 | } 16 | outSchema: inSchema 17 | inData: F: "abcde" 18 | outData: inData 19 | } 20 | -------------------------------------------------------------------------------- /cmd/avrogo/testdata/logicaltype.cue: -------------------------------------------------------------------------------- 1 | package roundtrip 2 | 3 | tests: timestampMicros: { 4 | inSchema: { 5 | type: "record" 6 | name: "R" 7 | fields: [{ 8 | name: "T" 9 | type: { 10 | type: "long" 11 | logicalType: "timestamp-micros" 12 | } 13 | }] 14 | } 15 | outSchema: inSchema 16 | inData: T: 1579176162000001 17 | outData: inData 18 | } 19 | 20 | tests: uuid: { 21 | inSchema: { 22 | type: "record" 23 | name: "R" 24 | fields: [{ 25 | name: "T" 26 | type: { 27 | type: "string" 28 | logicalType: "uuid" 29 | } 30 | }] 31 | } 32 | outSchema: inSchema 33 | inData: T: "6ba7b810-9dad-11d1-80b4-00c04fd430c8" 34 | outData: inData 35 | } 36 | 37 | tests: invalidUUID: { 38 | inSchema: { 39 | type: "record" 40 | name: "R" 41 | fields: [{ 42 | name: "T" 43 | type: { 44 | type: "string" 45 | logicalType: "uuid" 46 | } 47 | }] 48 | } 49 | outSchema: inSchema 50 | inData: T: "invalid_uuid" 51 | outData: null 52 | expectError: unmarshal: "invalid UUID in Avro encoding: invalid UUID length: 12" 53 | } 54 | 55 | tests: durationNanos: { 56 | inSchema: { 57 | type: "record" 58 | name: "R" 59 | fields: [{ 60 | name: "D" 61 | type: { 62 | type: "long" 63 | logicalType: "duration-nanos" 64 | } 65 | }] 66 | } 67 | outSchema: inSchema 68 | inData: D: 15000000000 69 | outData: inData 70 | } 71 | -------------------------------------------------------------------------------- /cmd/avrogo/testdata/map.cue: -------------------------------------------------------------------------------- 1 | package roundtrip 2 | 3 | tests: simpleMap: { 4 | inSchema: { 5 | type: "record" 6 | name: "R" 7 | fields: [{ 8 | name: "M" 9 | type: { 10 | type: "map" 11 | values: "int" 12 | } 13 | }] 14 | } 15 | outSchema: inSchema 16 | } 17 | 18 | tests: simpleMap: subtests: non_empty: { 19 | inData: M: { 20 | a: 32 21 | b: 54 22 | } 23 | outData: inData 24 | } 25 | 26 | tests: simpleMap: subtests: empty: { 27 | inData: M: {} 28 | outData: inData 29 | } 30 | -------------------------------------------------------------------------------- /cmd/avrogo/testdata/primitive.cue: -------------------------------------------------------------------------------- 1 | package roundtrip 2 | 3 | import "math/bits" 4 | 5 | tests: primitive: { 6 | inSchema: { 7 | type: "record" 8 | name: "R" 9 | fields: [{ 10 | name: "intField" 11 | type: "int" 12 | }, { 13 | name: "longField" 14 | type: "long" 15 | }, { 16 | name: "floatField" 17 | type: "float" 18 | }, { 19 | name: "doubleField" 20 | type: "double" 21 | }, { 22 | name: "boolField" 23 | type: "boolean" 24 | }, { 25 | name: "bytesField" 26 | type: "bytes" 27 | }, { 28 | name: "stringField" 29 | type: "string" 30 | }, { 31 | name: "nullField" 32 | type: "null" 33 | }] 34 | } 35 | outSchema: inSchema 36 | } 37 | 38 | tests: primitive: subtests: highValues: { 39 | inData: { 40 | intField: bits.Lsh(1, 31) - 1 41 | longField: bits.Lsh(1, 63) - 1 42 | floatField: 2e-10 43 | doubleField: 2e-50 44 | boolField: true 45 | // We'd include some binary data in the bytes field except for 46 | // https://github.com/linkedin/goavro/issues/192 47 | bytesField: "stuff" 48 | stringField: "hello world" 49 | nullField: null 50 | } 51 | outData: inData 52 | } 53 | 54 | tests: primitive: subtests: lowValues: { 55 | inData: { 56 | intField: -bits.Lsh(1, 31) 57 | longField: -bits.Lsh(1, 63) 58 | floatField: -2e-10 59 | doubleField: -2e-50 60 | boolField: false 61 | // We'd include some binary data in the bytes field except for 62 | // https://github.com/linkedin/goavro/issues/192 63 | bytesField: "" 64 | stringField: "" 65 | nullField: null 66 | } 67 | outData: inData 68 | } 69 | 70 | tests: primitiveIncompatible: { 71 | inSchema: { 72 | type: "record" 73 | name: "R" 74 | fields: [{ 75 | name: "f" 76 | type: "int" 77 | }] 78 | } 79 | outSchema: { 80 | type: "record" 81 | name: "R" 82 | fields: [{ 83 | name: "f" 84 | type: "string" 85 | }] 86 | } 87 | inData: f: 2134 88 | outData: null 89 | expectError: unmarshal: "cannot create decoder: Incompatible schemas: field f in reader has incompatible type in writer" 90 | } 91 | -------------------------------------------------------------------------------- /cmd/avrogo/testdata/recursive.cue: -------------------------------------------------------------------------------- 1 | package roundtrip 2 | 3 | tests: linkedList: { 4 | inSchema: { 5 | type: "record" 6 | name: "List" 7 | fields: [{ 8 | name: "Item" 9 | type: "int" 10 | }, { 11 | name: "Next" 12 | type: ["null", "List"] 13 | default: null 14 | }] 15 | } 16 | outSchema: inSchema 17 | inData: { 18 | Item: 1234 19 | Next: List: { 20 | Item: 9999 21 | Next: null 22 | } 23 | } 24 | outData: inData 25 | } 26 | 27 | tests: linkedListThenSomethingElse: { 28 | inSchema: { 29 | type: "record" 30 | name: "R" 31 | fields: [{ 32 | name: "L" 33 | type: { 34 | type: "record" 35 | name: "List" 36 | fields: [{ 37 | name: "Item" 38 | type: "int" 39 | }, { 40 | name: "Next" 41 | type: ["null", "List"] 42 | default: null 43 | }] 44 | } 45 | }, { 46 | name: "M" 47 | type: "int" 48 | }] 49 | } 50 | outSchema: inSchema 51 | inData: { 52 | L: { 53 | Item: 1234 54 | Next: List: { 55 | Item: 9999 56 | Next: null 57 | } 58 | } 59 | M: 1234 60 | } 61 | outData: inData 62 | } 63 | -------------------------------------------------------------------------------- /cmd/avrogo/testdata/schema/go.mod: -------------------------------------------------------------------------------- 1 | module dummy 2 | 3 | go 1.23 4 | 5 | require ( 6 | github.com/google/uuid v1.6.0 7 | github.com/heetch/avro v0.4.6-0.20241128170218-20b562ce498f 8 | github.com/heetch/galaxy-go/v2 v2.24.0 9 | ) 10 | 11 | require github.com/actgardner/gogen-avro/v10 v10.2.1 // indirect 12 | 13 | replace ( 14 | github.com/heetch/avro => ../../../.. 15 | ) 16 | -------------------------------------------------------------------------------- /cmd/avrogo/testdata/schema/go.sum: -------------------------------------------------------------------------------- 1 | github.com/actgardner/gogen-avro/v10 v10.2.1 h1:z3pOGblRjAJCYpkIJ8CmbMJdksi4rAhaygw0dyXZ930= 2 | github.com/actgardner/gogen-avro/v10 v10.2.1/go.mod h1:QUhjeHPchheYmMDni/Nx7VB0RsT/ee8YIgGY/xpEQgQ= 3 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 4 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 5 | github.com/heetch/avro v0.4.6-0.20241128170218-20b562ce498f h1:iK4+HtIuNeOEJsVBRMOmmEl9mVbnhbf2MYbvzvK22+E= 6 | github.com/heetch/avro v0.4.6-0.20241128170218-20b562ce498f/go.mod h1:gxf9GnbjTXmWmqxhdNbAMcZCjpye7RV5r9t3Q0dL6ws= 7 | github.com/heetch/galaxy-go/v2 v2.24.0 h1:qn5wIMWpFSogzQQ2SzvVoUrd1sc74U9xjbsjmbkWils= 8 | github.com/heetch/galaxy-go/v2 v2.24.0/go.mod h1:VSyZlEylS5T7UDPlaC9fjVvMz5qo0sh3JyHjajWyh9E= 9 | -------------------------------------------------------------------------------- /cmd/avrogo/testdata/schema/object.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "heetchmeta": { 3 | "version": 1 4 | }, 5 | "name": "Object", 6 | "namespace": "ns", 7 | "type": "record", 8 | "fields": [ 9 | { 10 | "doc": "Child1", 11 | "name": "Child1", 12 | "type": { 13 | "default": "UNSPECIFIED", 14 | "doc": "doc", 15 | "heetchmeta": { 16 | "skipRFC": true 17 | }, 18 | "name": "Child1", 19 | "namespace": "subns", 20 | "symbols": [ 21 | "UNSPECIFIED", 22 | "VALUE1", 23 | "VALUE2", 24 | "VALUE_EXTRA_1", 25 | "VALUE_EXTRA_2" 26 | ], 27 | "type": "enum" 28 | } 29 | }, 30 | { 31 | "default": "UNSPECIFIED", 32 | "name": "Child2", 33 | "type": { 34 | "name": "Child2", 35 | "symbols": [ 36 | "UNSPECIFIED", 37 | "STARTED", 38 | "COMPLETED", 39 | "FAILED", 40 | "ADDED_BY_OPERATOR" 41 | ], 42 | "type": "enum" 43 | } 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /cmd/avrogo/testdata/script/non-existent-output-dir.txt: -------------------------------------------------------------------------------- 1 | avrogo -p foo -d out/foo foo.avsc 2 | exists out/foo/foo_gen.go 3 | 4 | -- foo.avsc -- 5 | { 6 | "name": "R", 7 | "type": "record", 8 | "fields": [ 9 | { 10 | "name": "A", 11 | "type": "int" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /cmd/avrogo/testdata/testschema.cue: -------------------------------------------------------------------------------- 1 | package roundtrip 2 | 3 | import ( 4 | avroPkg "github.com/heetch/cue-schema/avro" 5 | ) 6 | 7 | avro :: avroPkg 8 | avro :: Metadata :: { 9 | "go.package"?: string 10 | "go.name"?: string 11 | heetchmeta?: { 12 | commentary: string 13 | status: string | *"active" 14 | partitions: int | *1 15 | topickey: string 16 | } 17 | } 18 | 19 | tests: [_]: roundTripTest 20 | 21 | tests: [name=_]: testName: name 22 | 23 | roundTripTest :: { 24 | testName: string 25 | inSchema: avro.Schema 26 | outSchema?: avro.Schema 27 | extraSchemas?: [... avro.Schema] 28 | goType: *outSchema.name | string 29 | goTypeBody?: string 30 | // generateError holds the error expected from invoking avrogo. 31 | // If this is specified, there will be no generated test package. 32 | generateError?: string 33 | inData?: _ 34 | outData?: _ 35 | expectError?: [errorKind]: string 36 | otherTests?: string 37 | subtests: [name=_]: { 38 | testName: name 39 | inData: _ 40 | outData: _ 41 | expectError?: [errorKind]: string 42 | } 43 | if inData != _|_ { 44 | subtests: main: { 45 | "inData": inData 46 | "outData": outData 47 | if expectError != _|_ { 48 | "expectError": expectError 49 | } 50 | } 51 | } 52 | } 53 | 54 | errorKind :: "unmarshal" | "marshal" 55 | -------------------------------------------------------------------------------- /cmd/avrogo/verify_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "os" 6 | "os/exec" 7 | "testing" 8 | 9 | qt "github.com/frankban/quicktest" 10 | 11 | "github.com/heetch/avro/cmd/avrogo/internal/avrotestdata" 12 | ) 13 | 14 | // Note: external command is called with three args: 15 | // in-schema, in-data, out-schema, all in JSON format 16 | // It's expected to produce JSON output with the round-tripped data. 17 | 18 | func TestExternalVerify(t *testing.T) { 19 | c := qt.New(t) 20 | verifyCmd := os.Getenv("AVRO_VERIFY") 21 | if verifyCmd == "" { 22 | c.Skip("$AVRO_VERIFY not set") 23 | } 24 | tests, err := avrotestdata.Load("./testdata") 25 | c.Assert(err, qt.Equals, nil) 26 | // Run tests in deterministic order by sorting keys. 27 | for _, test := range tests { 28 | test := test 29 | c.Run(test.TestName, func(c *qt.C) { 30 | if test.GoTypeBody != "" { 31 | c.Skip("test uses GoTypeBody") 32 | } 33 | if test.GenerateError != "" { 34 | c.Skip("test uses GenerateError") 35 | } 36 | inSchema := jsonMarshal(test.InSchema) 37 | outSchema := jsonMarshal(test.OutSchema) 38 | for _, subtest := range test.Subtests { 39 | subtest := subtest 40 | c.Run(subtest.TestName, func(c *qt.C) { 41 | if subtest.ExpectError != nil { 42 | c.Skip("subtest uses ExpectError") 43 | } 44 | inData := jsonMarshal(subtest.InData) 45 | c.Logf("run %s '%s' '%s' '%s'", verifyCmd, inSchema, outSchema, inData) 46 | cmd := exec.Command(verifyCmd, inSchema, outSchema, inData) 47 | var stdout, stderr bytes.Buffer 48 | cmd.Stdout = &stdout 49 | cmd.Stderr = &stderr 50 | err := cmd.Run() 51 | c.Assert(err, qt.Equals, nil, qt.Commentf("stderr:\n%s", &stderr)) 52 | c.Assert(stdout.Bytes(), qt.JSONEquals, subtest.OutData) 53 | }) 54 | } 55 | }) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /cmd/avsc2avdl/script_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | stdflag "flag" 5 | "os" 6 | "testing" 7 | 8 | "github.com/rogpeppe/go-internal/testscript" 9 | ) 10 | 11 | var updateScripts = stdflag.Bool("update-scripts", false, "update testdata/*.txt files with actual command output") 12 | 13 | func TestScript(t *testing.T) { 14 | testscript.Run(t, testscript.Params{ 15 | Dir: "testdata", 16 | UpdateScripts: *updateScripts, 17 | }) 18 | } 19 | 20 | func TestMain(m *testing.M) { 21 | os.Exit(testscript.RunMain(m, map[string]func() int{ 22 | "avsc2avdl": main1, 23 | })) 24 | } 25 | -------------------------------------------------------------------------------- /cmd/avsc2avdl/testdata/enumwarning.txt: -------------------------------------------------------------------------------- 1 | avsc2avdl -o out.avdl issue2866.avsc 2 | stderr '^out.avdl:3: WARNING: default value \("RED"\) for enum-valued field in R\.col will be ignored' 3 | cmp out.avdl expect.avdl 4 | -- expect.avdl -- 5 | protocol _ { 6 | record R { 7 | Color col = "RED"; 8 | } 9 | 10 | enum Color { 11 | RED, 12 | BLUE 13 | } 14 | } 15 | -- issue2866.avsc -- 16 | { 17 | "type" : "record", 18 | "name" : "R", 19 | "fields" : [ { 20 | "name" : "col", 21 | "default": "RED", 22 | "type" : { 23 | "type" : "enum", 24 | "name" : "Color", 25 | "symbols" : [ "RED", "BLUE" ] 26 | } 27 | } ] 28 | } -------------------------------------------------------------------------------- /cmd/avsc2avdl/testdata/recordwarning.txt: -------------------------------------------------------------------------------- 1 | avsc2avdl -o out.avdl issue2867.avsc 2 | stderr '^out.avdl:3: WARNING: default value \({\n\t"x": 1234\n}\) for record-valued field in R\.S will cause an exception' 3 | cmp out.avdl expect.avdl 4 | -- expect.avdl -- 5 | protocol _ { 6 | record R { 7 | S S = { 8 | "x": 1234 9 | }; 10 | } 11 | 12 | record S { 13 | int x; 14 | } 15 | } 16 | -- issue2867.avsc -- 17 | { 18 | "type" : "record", 19 | "name" : "R", 20 | "fields" : [ { 21 | "name" : "S", 22 | "default": {"x": 1234}, 23 | "type" : { 24 | "type" : "record", 25 | "name" : "S", 26 | "fields" : [ { 27 | "name" : "x", 28 | "type" : "int" 29 | } ] 30 | } 31 | } ] 32 | } 33 | -------------------------------------------------------------------------------- /cmd/avsc2avdl/testdata/simple.txt: -------------------------------------------------------------------------------- 1 | avsc2avdl test.avsc 2 | cmp stdout expect.avdl 3 | 4 | -- test.avsc -- 5 | { 6 | "type" : "record", 7 | "name" : "R", 8 | "namespace" : "ns1.sub", 9 | "doc" : "doc comment at top level", 10 | "fields" : [ { 11 | "name" : "fmap", 12 | "type" : { 13 | "type" : "map", 14 | "values" : "string", 15 | "fieldMetadata" : 245 16 | }, 17 | "doc" : "doc comment on field" 18 | }, { 19 | "name" : "fstrWithDefault", 20 | "type" : "string", 21 | "doc" : "* doc comment on field with\n * newline", 22 | "default" : "" 23 | }, { 24 | "name" : "fStrNoDefault", 25 | "type" : "string", 26 | "default" : "" 27 | }, { 28 | "name" : "fTime", 29 | "type" : { 30 | "type" : "long", 31 | "logicalType" : "timestamp-micros" 32 | }, 33 | "default" : 0 34 | }, { 35 | "name" : "fArray", 36 | "type" : { 37 | "type" : "array", 38 | "items" : "int" 39 | } 40 | }, { 41 | "name" : "fRef", 42 | "type" : { 43 | "type" : "record", 44 | "name" : "S", 45 | "namespace" : "ns2", 46 | "fields" : [ { 47 | "name" : "fs", 48 | "type" : "string" 49 | } ] 50 | } 51 | }, { 52 | "name" : "col", 53 | "type" : { 54 | "type" : "enum", 55 | "name" : "color", 56 | "namespace" : "ns3", 57 | "symbols" : [ "red", "blue", "green" ] 58 | }, 59 | "doc" : "Note: IDL doesn't support enum defaults! See https://issues.apache.org/jira/browse/AVRO-2866" 60 | }, { 61 | "name" : "checksum", 62 | "type" : { 63 | "type" : "fixed", 64 | "name" : "md5", 65 | "size" : 16 66 | } 67 | }, { 68 | "name" : "unionField", 69 | "type" : [ "null", "long", "ns2.S" ] 70 | }, { 71 | "name" : "smallUnionField", 72 | "type" : [ "null", "long" ] 73 | } ], 74 | "go.package" : "example.com/blah", 75 | "structuredMeta" : { 76 | "x" : 356, 77 | "y" : "foo" 78 | } 79 | } 80 | -- expect.avdl -- 81 | @namespace("ns1.sub") 82 | protocol _ { 83 | /** doc comment at top level */ 84 | @go.package("example.com/blah") 85 | @structuredMeta({ 86 | "x": 356, 87 | "y": "foo" 88 | }) 89 | record R { 90 | /** doc comment on field */ 91 | @fieldMetadata(245) 92 | map fmap; 93 | /** * doc comment on field with * newline */ 94 | string fstrWithDefault = ""; 95 | string fStrNoDefault = ""; 96 | @logicalType("timestamp-micros") 97 | long fTime = 0; 98 | array fArray; 99 | ns2.S fRef; 100 | /** Note: IDL doesn't support enum defaults! See https://issues.apache.org/jira/browse/AVRO-2866 */ 101 | ns3.color col; 102 | md5 checksum; 103 | union { 104 | null, 105 | long, 106 | ns2.S 107 | } unionField; 108 | union { null, long } smallUnionField; 109 | } 110 | 111 | @namespace("ns2") 112 | record S { 113 | string fs; 114 | } 115 | 116 | @namespace("ns3") 117 | enum color { 118 | red, 119 | blue, 120 | green 121 | } 122 | 123 | fixed md5(16); 124 | } 125 | -------------------------------------------------------------------------------- /cmd/go2avro/script_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/rogpeppe/go-internal/gotooltest" 8 | "github.com/rogpeppe/go-internal/testscript" 9 | ) 10 | 11 | func TestMain(m *testing.M) { 12 | os.Exit(testscript.RunMain(m, map[string]func() int{ 13 | "go2avro": main1, 14 | })) 15 | } 16 | 17 | func TestScript(t *testing.T) { 18 | p := testscript.Params{ 19 | Dir: "testdata", 20 | } 21 | if err := gotooltest.Setup(&p); err != nil { 22 | t.Fatal(err) 23 | } 24 | testscript.Run(t, p) 25 | } 26 | -------------------------------------------------------------------------------- /compat.go: -------------------------------------------------------------------------------- 1 | package avro 2 | 3 | // CompatMode defines a compatiblity mode used for checking Avro 4 | // type compatibility. 5 | type CompatMode int 6 | 7 | const ( 8 | Backward CompatMode = 1 << iota 9 | Forward 10 | Transitive 11 | 12 | BackwardTransitive = Backward | Transitive 13 | ForwardTransitive = Forward | Transitive 14 | Full = Backward | Forward 15 | FullTransitive = Full | Transitive 16 | ) 17 | 18 | // String returns a string representation of m, one of the values defined 19 | // in https://docs.confluent.io/current/schema-registry/avro.html#schema-evolution-and-compatibility. 20 | // For example FullTransitive.String() returns "FULL_TRANSITIVE". 21 | func (m CompatMode) String() string { 22 | var s string 23 | switch m &^ Transitive { 24 | case 0: 25 | return "NONE" 26 | case Backward: 27 | s = "BACKWARD" 28 | case Forward: 29 | s = "FORWARD" 30 | case Backward | Forward: 31 | s = "FULL" 32 | default: 33 | return "UNKNOWN" 34 | } 35 | if m&Transitive != 0 { 36 | s += "_TRANSITIVE" 37 | } 38 | return s 39 | } 40 | 41 | // ParseCompatMode returns the CompatMode from a string. 42 | // It returns -1 if no matches are found. 43 | func ParseCompatMode(s string) CompatMode { 44 | switch s { 45 | case "BACKWARD": 46 | return Backward 47 | case "FORWARD": 48 | return Forward 49 | case "FULL": 50 | return Full 51 | case "BACKWARD_TRANSITIVE": 52 | return BackwardTransitive 53 | case "FORWARD_TRANSITIVE": 54 | return ForwardTransitive 55 | case "FULL_TRANSITIVE": 56 | return FullTransitive 57 | case "NONE": 58 | return 0 59 | } 60 | return -1 61 | } 62 | -------------------------------------------------------------------------------- /compat_test.go: -------------------------------------------------------------------------------- 1 | package avro_test 2 | 3 | import ( 4 | "testing" 5 | 6 | qt "github.com/frankban/quicktest" 7 | 8 | "github.com/heetch/avro" 9 | ) 10 | 11 | var compatStringTests = []struct { 12 | m avro.CompatMode 13 | s string 14 | }{ 15 | {0, "NONE"}, 16 | {avro.Backward, "BACKWARD"}, 17 | {avro.Forward, "FORWARD"}, 18 | {avro.Full, "FULL"}, 19 | {avro.BackwardTransitive, "BACKWARD_TRANSITIVE"}, 20 | {avro.ForwardTransitive, "FORWARD_TRANSITIVE"}, 21 | {avro.FullTransitive, "FULL_TRANSITIVE"}, 22 | {1 << 10, "UNKNOWN"}, 23 | } 24 | 25 | func TestCompatString(t *testing.T) { 26 | c := qt.New(t) 27 | for _, test := range compatStringTests { 28 | c.Run(test.s, func(c *qt.C) { 29 | c.Assert(test.m.String(), qt.Equals, test.s) 30 | }) 31 | } 32 | } 33 | 34 | func TestCompatParse(t *testing.T) { 35 | c := qt.New(t) 36 | for _, test := range compatStringTests { 37 | c.Run(test.s, func(c *qt.C) { 38 | if test.s == "UNKNOWN" { 39 | // We can't return same data we don't know 40 | c.Assert(avro.ParseCompatMode(test.s), qt.Equals, avro.CompatMode(-1)) 41 | } else { 42 | c.Assert(avro.ParseCompatMode(test.s), qt.Equals, test.m) 43 | } 44 | }) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /cover.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # show coverage of the base Avro package with respect to all generated 3 | # test packages. 4 | 5 | f=$(mktemp) 6 | go test -coverpkg ./... -coverprofile $f ./... && go tool cover -html $f 7 | rm $f 8 | -------------------------------------------------------------------------------- /cue.mod/module.cue: -------------------------------------------------------------------------------- 1 | module: "" 2 | -------------------------------------------------------------------------------- /cue.mod/pkg/github.com/heetch/cue-schema/avro/protocol.cue: -------------------------------------------------------------------------------- 1 | package avro 2 | 3 | Protocol :: { 4 | protocol: string 5 | namespace?: string 6 | doc?: string 7 | types: [... Schema] 8 | messages?: { 9 | [string]: Message 10 | } 11 | } 12 | 13 | Message :: { 14 | doc?: string 15 | request: [... Field] 16 | response: Schema 17 | errors?: [... Schema] 18 | if (response & "null") != _|_ { 19 | "one-way"?: bool 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /cue.mod/pkg/github.com/heetch/cue-schema/cue.mod/module.cue: -------------------------------------------------------------------------------- 1 | module: "github.com/heetch/cue-schema" 2 | -------------------------------------------------------------------------------- /cue.mod/pkg/github.com/heetch/cue-schema/github/cue.mod/module.cue: -------------------------------------------------------------------------------- 1 | module: "github.com/heetch/cue-schema/github" 2 | -------------------------------------------------------------------------------- /cue.mod/pkg/github.com/heetch/cue-schema/github/generate/generate-workflow.cue: -------------------------------------------------------------------------------- 1 | package generate 2 | 3 | import ( 4 | "tool/file" 5 | "encoding/yaml" 6 | "github.com/heetch/cue-schema/github/workflow" 7 | ) 8 | 9 | Workflow :: workflow 10 | 11 | command: generateworkflow: { 12 | task: write: file.Create & { 13 | filename: ".github/workflows/test.yaml" 14 | contents: """ 15 | // Code generated by github.com/heetch/cue-schema/github/workflow/generate. DO NOT EDIT. 16 | \(yaml.Marshal(Workflow)) 17 | """ 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cue.mod/pkg/github.com/heetch/cue-schema/github/workflow/example/go/.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/heetch/cue-schema/github/workflow/generate. DO NOT EDIT. 2 | jobs: 3 | test: 4 | runs-on: ${{ matrix.platform }} 5 | services: 6 | kafka: 7 | env: 8 | KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092 9 | KAFKA_BROKER_ID: "1" 10 | KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT 11 | KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT 12 | KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: "1" 13 | KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 14 | image: confluentinc/cp-kafka:latest 15 | postgres: 16 | env: 17 | POSTGRES_DB: postgres 18 | POSTGRES_PASSWORD: postgres 19 | POSTGRES_USER: postgres 20 | image: postgres:10.8 21 | options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s 22 | --health-retries 5 23 | ports: 24 | - 5432:5432 25 | steps: 26 | - name: Install Go 27 | uses: actions/setup-go@v1 28 | with: 29 | go-version: ${{ matrix.go-version }} 30 | - name: Checkout code 31 | uses: actions/checkout@v1 32 | - name: Test 33 | run: go test ./... 34 | strategy: 35 | matrix: 36 | go-version: 37 | - v1.12.x 38 | - v1.13.x 39 | platform: 40 | - ubuntu-latest 41 | name: My CI caboodle 42 | "on": 43 | - push 44 | - pull_request 45 | -------------------------------------------------------------------------------- /cue.mod/pkg/github.com/heetch/cue-schema/github/workflow/example/go/ci.yaml: -------------------------------------------------------------------------------- 1 | jobs: 2 | test: 3 | runs-on: ${{ matrix.platform }} 4 | services: 5 | kafka: 6 | env: 7 | KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092 8 | KAFKA_BROKER_ID: "1" 9 | KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT 10 | KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT 11 | KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: "1" 12 | KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 13 | image: confluentinc/cp-kafka:latest 14 | postgres: 15 | env: 16 | POSTGRES_DB: postgres 17 | POSTGRES_PASSWORD: postgres 18 | POSTGRES_USER: postgres 19 | image: postgres:10.8 20 | options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s 21 | --health-retries 5 22 | ports: 23 | - 5432:5432 24 | steps: 25 | - name: Install Go 26 | uses: actions/setup-go@v1 27 | with: 28 | go-version: ${{ matrix.go-version }} 29 | - name: Checkout code 30 | uses: actions/checkout@v1 31 | - name: Test 32 | run: go test ./... 33 | strategy: 34 | matrix: 35 | go-version: 36 | - go1.13.4 37 | platform: 38 | - ubuntu-latest 39 | name: My CI caboodle 40 | "on": 41 | - push 42 | - pull_request 43 | -------------------------------------------------------------------------------- /cue.mod/pkg/github.com/heetch/cue-schema/github/workflow/example/go/go.cue: -------------------------------------------------------------------------------- 1 | package go 2 | import ( 3 | goworkflow "github.com/heetch/cue-schema/github/workflow/go:workflow" 4 | ) 5 | 6 | Workflow :: goworkflow 7 | Workflow :: { 8 | name: "My CI caboodle" 9 | Versions :: ["v1.12", "v1.13"] 10 | Services :: ["postgres", "kafka"] 11 | } 12 | -------------------------------------------------------------------------------- /cue.mod/pkg/github.com/heetch/cue-schema/github/workflow/workflow.cue: -------------------------------------------------------------------------------- 1 | // Package workflow describes the contents of a file in the 2 | // .github/workflows directory of a repository. 3 | // 4 | // This follows the API described here: 5 | // https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions 6 | package workflow 7 | 8 | // TODO cross-verify against https://github.com/SchemaStore/schemastore/blob/master/src/schemas/json/github-workflow.json 9 | 10 | import "regexp" 11 | 12 | // name holds the name of your workflow. GitHub displays the 13 | // names of your workflows on your repository's actions page. If 14 | // you omit this field, GitHub sets the name to the workflow's 15 | // filename. 16 | name?: string 17 | 18 | // On describes the event or events that trigger the workflow. 19 | on: Event | [... Event] | EventConfig 20 | 21 | env?: Env 22 | jobs: { 23 | // TODO must start with a letter or _ and contain only alphanumeric characters, -, or _. 24 | : Job 25 | } 26 | 27 | // Job represents one of the jobs to do as part of the action. 28 | Job :: { 29 | name?: string 30 | // TODO restrict JobID to names mentioned in the workflow jobs? 31 | needs?: JobID | [...JobID] 32 | "runs-on"?: string | [string, ...string] 33 | env?: Env 34 | if?: Condition 35 | steps?: [... JobStep] 36 | "timeout-minutes"?: number 37 | container?: { 38 | image?: string 39 | env?: Env 40 | ports?: [ ... int] 41 | volumes?: [ ... string] 42 | options?: _ // TODO more specific type here 43 | } 44 | strategy?: { 45 | matrix: { 46 | : [ ...] 47 | } 48 | "fail-fast"?: bool 49 | "max-parallel"?: int & >0 50 | } 51 | services: { 52 | [_]: Service 53 | } 54 | } 55 | 56 | Service :: { 57 | image: string 58 | env?: Env 59 | ports?: [... string] 60 | volumes?: [ ... string] 61 | options?: _ // TODO more specific type here 62 | 63 | } 64 | 65 | JobStep :: { 66 | id?: string 67 | if?: Condition 68 | name?: string 69 | uses?: string 70 | run?: string 71 | "working-directory"?: string 72 | shell?: 73 | "bash" | 74 | "pwsh" | 75 | "python" | 76 | "sh" | 77 | "cmd" | 78 | "powershell" | 79 | regexp.Match(#"\{0\}"#) 80 | 81 | // with holds a map of the input parameters defined by the action. 82 | // Each input parameter is a key/value pair. Input parameters are 83 | // set as environment variables. The variable is prefixed with INPUT_ 84 | // and converted to upper case. 85 | with?: {<_>: string} 86 | env?: Env 87 | "continue-on-error"?: bool 88 | "timeout-minutes"?: number 89 | } 90 | 91 | // JobID represents one the of jobs specified in Workflow. 92 | JobID :: string 93 | 94 | // Condition represents a condition to evaluate. 95 | // TODO link to syntax. 96 | Condition :: string 97 | 98 | // Env represents a set of environment variables and their values. 99 | Env :: { 100 | <_>: string 101 | } 102 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package avro provides encoding and decoding for the Avro binary data format. 3 | 4 | The format uses out-of-band schemas to determine the encoding, 5 | with a schema migration scheme to allow data written with 6 | one schema to be read using another schema. 7 | 8 | See here for more information on the format: 9 | 10 | https://avro.apache.org/docs/1.9.1/spec.html 11 | 12 | This package provides a mapping from regular Go types 13 | to Avro schemas. See the TypeOf function for more details. 14 | 15 | There is also a code generation tool that can generate 16 | Go data structures from Avro schemas. 17 | See https://pkg.go.dev/github.com/heetch/avro/cmd/avrogo 18 | for details. 19 | */ 20 | package avro 21 | -------------------------------------------------------------------------------- /github-action.cue: -------------------------------------------------------------------------------- 1 | package avroCI 2 | -------------------------------------------------------------------------------- /github-action_tool.cue: -------------------------------------------------------------------------------- 1 | package avroCI 2 | 3 | import ( 4 | "tool/file" 5 | "encoding/yaml" 6 | workflow "github.com/heetch/cue-schema/github/workflow/go:workflow" 7 | ) 8 | 9 | ci: workflow 10 | 11 | ci: RunTest :: """ 12 | set -ex 13 | tgz=$(mktemp) 14 | ARCH="$(uname -s)_$(uname -m)" 15 | mkdir -p ~/go/bin 16 | export PATH=$PATH:~/go/bin 17 | curl "https://github.com/cuelang/cue/releases/download/v0.0.15/cue_0.0.15_$ARCH.tar.gz" -L -o $tgz 18 | (cd ~/go/bin && tar xzf $tgz cue) 19 | go install ./cmd/... && 20 | go generate . ./cmd/... && 21 | go test ./... 22 | """ 23 | 24 | command: generateworkflow: { 25 | task: write: file.Create & { 26 | filename: ".github/workflows/test.yaml" 27 | contents: """ 28 | # Code generated by github.com/heetch/cue-schema/github/workflow/generate. DO NOT EDIT. 29 | \(yaml.Marshal(ci)) 30 | """ 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/heetch/avro 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/actgardner/gogen-avro/v10 v10.2.1 7 | github.com/frankban/quicktest v1.14.0 8 | github.com/google/uuid v1.6.0 9 | github.com/kr/pretty v0.3.0 10 | github.com/linkedin/goavro/v2 v2.11.1 11 | github.com/rogpeppe/go-internal v1.14.1 12 | github.com/sebdah/goldie/v2 v2.5.5 13 | github.com/stretchr/testify v1.7.1 14 | golang.org/x/text v0.23.0 15 | gopkg.in/httprequest.v1 v1.2.1 16 | gopkg.in/retry.v1 v1.0.3 17 | ) 18 | 19 | require ( 20 | github.com/davecgh/go-spew v1.1.1 // indirect 21 | github.com/golang/snappy v0.0.4 // indirect 22 | github.com/google/go-cmp v0.6.0 // indirect 23 | github.com/julienschmidt/httprouter v1.3.0 // indirect 24 | github.com/kr/text v0.2.0 // indirect 25 | github.com/pmezard/go-difflib v1.0.0 // indirect 26 | github.com/sergi/go-diff v1.0.0 // indirect 27 | golang.org/x/net v0.33.0 // indirect 28 | golang.org/x/sys v0.28.0 // indirect 29 | golang.org/x/tools v0.26.0 // indirect 30 | gopkg.in/errgo.v1 v1.0.0 // indirect 31 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 32 | ) 33 | -------------------------------------------------------------------------------- /internal/testtypes/cloudevent.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.heetch.Message", 3 | "type": "record", 4 | "fields": [ 5 | { 6 | "name": "Metadata", 7 | "type": { 8 | "name": "Metadata", 9 | "type": "record", 10 | "fields": [ 11 | { 12 | "name": "CloudEvent", 13 | "type": { 14 | "name": "CloudEvent", 15 | "type": "record", 16 | "fields": [ 17 | { 18 | "name": "time", 19 | "type": { 20 | "type": "long", 21 | "logicalType": "timestamp-micros" 22 | } 23 | }, 24 | { 25 | "name": "id", 26 | "type": "string" 27 | }, 28 | { 29 | "name": "specversion", 30 | "type": "string" 31 | }, 32 | { 33 | "name": "source", 34 | "type": "string" 35 | }, 36 | { 37 | "name": "extraField", 38 | "type": "boolean" 39 | } 40 | ] 41 | } 42 | } 43 | ] 44 | } 45 | } 46 | ] 47 | } 48 | -------------------------------------------------------------------------------- /internal/testtypes/cloudevent_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package testtypes 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | "time" 8 | ) 9 | 10 | type CloudEvent struct { 11 | Time time.Time `json:"time"` 12 | Id string `json:"id"` 13 | Specversion string `json:"specversion"` 14 | Source string `json:"source"` 15 | ExtraField bool `json:"extraField"` 16 | } 17 | 18 | // AvroRecord implements the avro.AvroRecord interface. 19 | func (CloudEvent) AvroRecord() avrotypegen.RecordInfo { 20 | return avrotypegen.RecordInfo{ 21 | Schema: `{"fields":[{"name":"time","type":{"logicalType":"timestamp-micros","type":"long"}},{"name":"id","type":"string"},{"name":"specversion","type":"string"},{"name":"source","type":"string"},{"name":"extraField","type":"boolean"}],"name":"com.heetch.CloudEvent","type":"record"}`, 22 | Required: []bool{ 23 | 0: true, 24 | 1: true, 25 | 2: true, 26 | 3: true, 27 | 4: true, 28 | }, 29 | } 30 | } 31 | 32 | type Message struct { 33 | Metadata Metadata 34 | } 35 | 36 | // AvroRecord implements the avro.AvroRecord interface. 37 | func (Message) AvroRecord() avrotypegen.RecordInfo { 38 | return avrotypegen.RecordInfo{ 39 | Schema: `{"fields":[{"name":"Metadata","type":{"fields":[{"name":"CloudEvent","type":{"fields":[{"name":"time","type":{"logicalType":"timestamp-micros","type":"long"}},{"name":"id","type":"string"},{"name":"specversion","type":"string"},{"name":"source","type":"string"},{"name":"extraField","type":"boolean"}],"name":"CloudEvent","type":"record"}}],"name":"Metadata","type":"record"}}],"name":"com.heetch.Message","type":"record"}`, 40 | Required: []bool{ 41 | 0: true, 42 | }, 43 | } 44 | } 45 | 46 | type Metadata struct { 47 | CloudEvent CloudEvent 48 | } 49 | 50 | // AvroRecord implements the avro.AvroRecord interface. 51 | func (Metadata) AvroRecord() avrotypegen.RecordInfo { 52 | return avrotypegen.RecordInfo{ 53 | Schema: `{"fields":[{"name":"CloudEvent","type":{"fields":[{"name":"time","type":{"logicalType":"timestamp-micros","type":"long"}},{"name":"id","type":"string"},{"name":"specversion","type":"string"},{"name":"source","type":"string"},{"name":"extraField","type":"boolean"}],"name":"CloudEvent","type":"record"}}],"name":"com.heetch.Metadata","type":"record"}`, 54 | Required: []bool{ 55 | 0: true, 56 | }, 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /internal/testtypes/enum_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type Enum -trimprefix Enum"; DO NOT EDIT. 2 | 3 | package testtypes 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[EnumOne-0] 12 | _ = x[EnumTwo-1] 13 | _ = x[EnumThree-2] 14 | } 15 | 16 | const _Enum_name = "OneTwoThree" 17 | 18 | var _Enum_index = [...]uint8{0, 3, 6, 11} 19 | 20 | func (i Enum) String() string { 21 | if i < 0 || i >= Enum(len(_Enum_index)-1) { 22 | return "Enum(" + strconv.FormatInt(int64(i), 10) + ")" 23 | } 24 | return _Enum_name[_Enum_index[i]:_Enum_index[i+1]] 25 | } 26 | -------------------------------------------------------------------------------- /internal/testtypes/generate.go: -------------------------------------------------------------------------------- 1 | package testtypes 2 | 3 | //go:generate avrogo cloudevent.avsc 4 | -------------------------------------------------------------------------------- /internal/testtypes/proto.go: -------------------------------------------------------------------------------- 1 | package testtypes 2 | 3 | import "strconv" 4 | 5 | // This file contains code copied from github.com/gogo/protobuf/proto 6 | // so that we can avoid that dependency. 7 | 8 | // ProtoEnumName is a helper function to simplify printing protocol buffer enums 9 | // by name. Given an enum map and a value, it returns a useful string. 10 | func ProtoEnumName(m map[int32]string, v int32) string { 11 | s, ok := m[v] 12 | if ok { 13 | return s 14 | } 15 | return strconv.Itoa(int(v)) 16 | } 17 | 18 | type ProtoMessage struct{} 19 | -------------------------------------------------------------------------------- /internal/testtypes/prototest1.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package arble.foo.v1; 4 | 5 | option go_package = "testtypes"; 6 | 7 | // MessageA has a doc comment. 8 | message MessageA { 9 | string id = 1; 10 | LabelFor label = 2; 11 | string foo_url = 3; 12 | bool enabled = 4; 13 | } 14 | 15 | // UserDisability is used to show whether a disability has been selected by a user. 16 | message MessageB { 17 | MessageA arble = 1; 18 | bool selected = 2; 19 | } 20 | 21 | // LabelFor also has a doc comment. 22 | enum LabelFor { 23 | LABEL_FOR_ZERO = 0; 24 | LABEL_FOR_ONE = 1; 25 | LABEL_FOR_TWO = 2; 26 | LABEL_FOR_THREE = 3; 27 | } 28 | -------------------------------------------------------------------------------- /internal/testtypes/prototool.yaml: -------------------------------------------------------------------------------- 1 | protoc: 2 | version: 3.8.0 3 | lint: 4 | group: uber2 5 | ignores: 6 | - id: NAMES_NO_UUID 7 | files: 8 | - user/identifier 9 | rules: 10 | remove: 11 | - FILE_OPTIONS_CSHARP_NAMESPACE_SAME_IN_DIR 12 | - FILE_OPTIONS_EQUAL_CSHARP_NAMESPACE_CAPITALIZED 13 | - FILE_OPTIONS_EQUAL_JAVA_MULTIPLE_FILES_TRUE 14 | - FILE_OPTIONS_EQUAL_JAVA_OUTER_CLASSNAME_PROTO_SUFFIX 15 | - FILE_OPTIONS_EQUAL_JAVA_PACKAGE_PREFIX 16 | - FILE_OPTIONS_EQUAL_OBJC_CLASS_PREFIX_ABBR 17 | - FILE_OPTIONS_EQUAL_PHP_NAMESPACE_CAPITALIZED 18 | - FILE_OPTIONS_JAVA_MULTIPLE_FILES_SAME_IN_DIR 19 | - FILE_OPTIONS_JAVA_PACKAGE_SAME_IN_DIR 20 | - FILE_OPTIONS_OBJC_CLASS_PREFIX_SAME_IN_DIR 21 | - FILE_OPTIONS_PHP_NAMESPACE_SAME_IN_DIR 22 | - FILE_OPTIONS_REQUIRE_CSHARP_NAMESPACE 23 | - FILE_OPTIONS_REQUIRE_JAVA_MULTIPLE_FILES 24 | - FILE_OPTIONS_REQUIRE_JAVA_OUTER_CLASSNAME 25 | - FILE_OPTIONS_REQUIRE_JAVA_PACKAGE 26 | - FILE_OPTIONS_REQUIRE_OBJC_CLASS_PREFIX 27 | - FILE_OPTIONS_REQUIRE_PHP_NAMESPACE 28 | 29 | generate: 30 | go_options: 31 | import_path: github.com/heetch/proto 32 | plugins: 33 | - name: gogo 34 | type: gogo 35 | flags: plugins=grpc 36 | output: . 37 | -------------------------------------------------------------------------------- /internal/testtypes/testtypes.go: -------------------------------------------------------------------------------- 1 | // Package testtypes defines types for testing the avro package 2 | // that aren't easily defined in the test package there. 3 | // 4 | // Note: stringer doesn't work on test files, and we want to make sure 5 | // that enum detection works ok on stringer-generated String methods, 6 | // hence the reason for this package. 7 | package testtypes 8 | 9 | //go:generate stringer -type Enum -trimprefix Enum 10 | 11 | type Enum int 12 | 13 | const ( 14 | EnumOne Enum = iota 15 | EnumTwo 16 | EnumThree 17 | ) 18 | -------------------------------------------------------------------------------- /internal/typeinfo/schema.go: -------------------------------------------------------------------------------- 1 | package typeinfo 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/actgardner/gogen-avro/v10/parser" 7 | "github.com/actgardner/gogen-avro/v10/resolver" 8 | "github.com/actgardner/gogen-avro/v10/schema" 9 | ) 10 | 11 | // ParseSchema parses the given Avro type and resolves 12 | // all its references. 13 | // If ns is non-nil, it will be used as the namespace for 14 | // the definitions. 15 | func ParseSchema(s string, ns *parser.Namespace) (schema.AvroType, error) { 16 | // TODO this function doesn't really belong in the typeinfo package 17 | // but it doesn't seem worth making a new package just for this. 18 | if ns == nil { 19 | ns = parser.NewNamespace(false) 20 | } 21 | avroType, err := ns.TypeForSchema([]byte(s)) 22 | if err != nil { 23 | return nil, fmt.Errorf("invalid schema %q: %v", s, err) 24 | } 25 | for _, def := range ns.Roots { 26 | if err := resolver.ResolveDefinition(def, ns.Definitions); err != nil { 27 | return nil, fmt.Errorf("cannot resolve references in schema\n%s\n: %v", s, err) 28 | } 29 | } 30 | return avroType, nil 31 | } 32 | -------------------------------------------------------------------------------- /reader_test.go: -------------------------------------------------------------------------------- 1 | package avro 2 | 3 | import ( 4 | "io" 5 | "strings" 6 | "testing" 7 | "testing/iotest" 8 | 9 | qt "github.com/frankban/quicktest" 10 | ) 11 | 12 | func TestReadFixed(t *testing.T) { 13 | c := qt.New(t) 14 | d := &decoder{ 15 | buf: make([]byte, 0, 10), 16 | r: iotest.OneByteReader(strings.NewReader("abcdefghijklmnopqrstuvwxyz")), 17 | } 18 | b := d.readFixed(5) 19 | c.Assert(string(b), qt.Equals, "abcde") 20 | b = d.readFixed(3) 21 | c.Assert(string(b), qt.Equals, "fgh") 22 | b = d.readFixed(5) 23 | c.Assert(string(b), qt.Equals, "ijklm") 24 | p := catch(func() { 25 | d.readFixed(30) 26 | }) 27 | c.Assert(p, qt.Not(qt.IsNil)) 28 | c.Assert(p.(*decodeError).err, qt.Equals, io.ErrUnexpectedEOF) 29 | } 30 | 31 | func catch(f func()) (v interface{}) { 32 | defer func() { 33 | v = recover() 34 | }() 35 | f() 36 | return 37 | } 38 | -------------------------------------------------------------------------------- /singleencoder.go: -------------------------------------------------------------------------------- 1 | package avro 2 | 3 | import ( 4 | "context" 5 | "reflect" 6 | "sync" 7 | ) 8 | 9 | // EncodingRegistry is used by SingleEncoder to find 10 | // ids for schemas encoded in messages. 11 | type EncodingRegistry interface { 12 | // AppendSchemaID appends the given schema ID header to buf 13 | // and returns the resulting slice. 14 | AppendSchemaID(buf []byte, id int64) []byte 15 | 16 | // IDForSchema returns an ID for the given schema. 17 | IDForSchema(ctx context.Context, schema *Type) (int64, error) 18 | } 19 | 20 | // SingleEncoder encodes messages in Avro binary format. 21 | // Each message includes a header or wrapper that indicates the schema. 22 | type SingleEncoder struct { 23 | registry EncodingRegistry 24 | names *Names 25 | // ids holds a map from Go type (reflect.Type) to schema ID (int64) 26 | ids sync.Map 27 | } 28 | 29 | // NewSingleEncoder returns a SingleEncoder instance that encodes single 30 | // messages along with their schema identifier. 31 | // 32 | // Go values unmarshaled through Marshal will have their Avro schemas 33 | // translated with the given Names instance. If names is nil, the global 34 | // namespace will be used. 35 | func NewSingleEncoder(r EncodingRegistry, names *Names) *SingleEncoder { 36 | if names == nil { 37 | names = globalNames 38 | } 39 | return &SingleEncoder{ 40 | registry: r, 41 | names: names, 42 | } 43 | } 44 | 45 | // CheckMarshalType checks that the given type can be marshaled with the encoder. 46 | // It also caches any type information obtained from the EncodingRegistry from the 47 | // type, so future calls to Marshal with that type won't call it. 48 | func (enc *SingleEncoder) CheckMarshalType(ctx context.Context, x interface{}) error { 49 | _, err := enc.idForType(ctx, reflect.TypeOf(x)) 50 | return err 51 | } 52 | 53 | // Marshal returns x marshaled as using the Avro binary encoding, 54 | // along with an identifier that records the type that it was encoded 55 | // with. 56 | func (enc *SingleEncoder) Marshal(ctx context.Context, x interface{}) ([]byte, error) { 57 | xv := reflect.ValueOf(x) 58 | id, err := enc.idForType(ctx, xv.Type()) 59 | if err != nil { 60 | return nil, err 61 | } 62 | buf := make([]byte, 0, 100) 63 | buf = enc.registry.AppendSchemaID(buf, id) 64 | data, _, err := marshalAppend(enc.names, buf, xv) 65 | return data, err 66 | } 67 | 68 | func (enc *SingleEncoder) idForType(ctx context.Context, t reflect.Type) (int64, error) { 69 | id, ok := enc.ids.Load(t) 70 | if ok { 71 | return id.(int64), nil 72 | } 73 | avroType, err := avroTypeOf(enc.names, t) 74 | if err != nil { 75 | return 0, err 76 | } 77 | id1, err := enc.registry.IDForSchema(ctx, avroType) 78 | if err != nil { 79 | return 0, err 80 | } 81 | enc.ids.LoadOrStore(t, id1) 82 | return id1, nil 83 | } 84 | -------------------------------------------------------------------------------- /testschema1.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TestRecord", 3 | "type": "record", 4 | "fields": [{ 5 | "name": "A", 6 | "type": { 7 | "type": "int" 8 | }, 9 | "default": 42 10 | }, { 11 | "name": "B", 12 | "type": { 13 | "type": "int" 14 | } 15 | }] 16 | } 17 | -------------------------------------------------------------------------------- /testschema1_gen_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package avro_test 4 | 5 | import ( 6 | "github.com/heetch/avro/avrotypegen" 7 | ) 8 | 9 | type TestRecord struct { 10 | A int 11 | B int 12 | } 13 | 14 | // AvroRecord implements the avro.AvroRecord interface. 15 | func (TestRecord) AvroRecord() avrotypegen.RecordInfo { 16 | return avrotypegen.RecordInfo{ 17 | Schema: `{"fields":[{"default":42,"name":"A","type":{"type":"int"}},{"name":"B","type":{"type":"int"}}],"name":"TestRecord","type":"record"}`, 18 | Required: []bool{ 19 | 1: true, 20 | }, 21 | Defaults: []func() interface{}{ 22 | 0: func() interface{} { 23 | return 42 24 | }, 25 | }, 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /testschema2.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TestNewRecord", 3 | "type": "record", 4 | "fields": [{ 5 | "name": "A", 6 | "type": { 7 | "type": "int" 8 | }, 9 | "default": 42 10 | }, { 11 | "name": "B", 12 | "type": { 13 | "type": "int" 14 | } 15 | }, { 16 | "name": "C", 17 | "type": [ 18 | "null", 19 | { 20 | "name": "EnumC", 21 | "type": "enum", 22 | "symbols": ["x", "y", "z"] 23 | } 24 | ], 25 | "default": null 26 | }] 27 | } 28 | -------------------------------------------------------------------------------- /testschema2_gen_test.go: -------------------------------------------------------------------------------- 1 | // Code generated by avrogen. DO NOT EDIT. 2 | 3 | package avro_test 4 | 5 | import ( 6 | "fmt" 7 | "github.com/heetch/avro/avrotypegen" 8 | "strconv" 9 | ) 10 | 11 | type EnumC int 12 | 13 | const ( 14 | EnumCX EnumC = iota 15 | EnumCY 16 | EnumCZ 17 | ) 18 | 19 | var _EnumC_strings = []string{ 20 | "x", 21 | "y", 22 | "z", 23 | } 24 | 25 | // String returns the textual representation of EnumC. 26 | func (e EnumC) String() string { 27 | if e < 0 || int(e) >= len(_EnumC_strings) { 28 | return "EnumC(" + strconv.FormatInt(int64(e), 10) + ")" 29 | } 30 | return _EnumC_strings[e] 31 | } 32 | 33 | // MarshalText implements encoding.TextMarshaler 34 | // by returning the textual representation of EnumC. 35 | func (e EnumC) MarshalText() ([]byte, error) { 36 | if e < 0 || int(e) >= len(_EnumC_strings) { 37 | return nil, fmt.Errorf("EnumC value %d is out of bounds", e) 38 | } 39 | return []byte(_EnumC_strings[e]), nil 40 | } 41 | 42 | // UnmarshalText implements encoding.TextUnmarshaler 43 | // by expecting the textual representation of EnumC. 44 | func (e *EnumC) UnmarshalText(data []byte) error { 45 | // Note for future: this could be more efficient. 46 | for i, s := range _EnumC_strings { 47 | if string(data) == s { 48 | *e = EnumC(i) 49 | return nil 50 | } 51 | } 52 | return fmt.Errorf("unknown value %q for EnumC", data) 53 | } 54 | 55 | type TestNewRecord struct { 56 | A int 57 | B int 58 | C *EnumC 59 | } 60 | 61 | // AvroRecord implements the avro.AvroRecord interface. 62 | func (TestNewRecord) AvroRecord() avrotypegen.RecordInfo { 63 | return avrotypegen.RecordInfo{ 64 | Schema: `{"fields":[{"default":42,"name":"A","type":{"type":"int"}},{"name":"B","type":{"type":"int"}},{"default":null,"name":"C","type":["null",{"name":"EnumC","symbols":["x","y","z"],"type":"enum"}]}],"name":"TestNewRecord","type":"record"}`, 65 | Required: []bool{ 66 | 1: true, 67 | }, 68 | Defaults: []func() interface{}{ 69 | 0: func() interface{} { 70 | return 42 71 | }, 72 | }, 73 | } 74 | } 75 | --------------------------------------------------------------------------------