| /* |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| */ |
| |
| // Test that conversion of Go type to/from AMQP is compatible with other |
| // bindings. |
| // |
| package amqp |
| |
| import ( |
| "bytes" |
| "io" |
| "io/ioutil" |
| "os" |
| "reflect" |
| "strings" |
| "testing" |
| |
| "github.com/apache/qpid-proton/go/pkg/internal/test" |
| ) |
| |
| var skipped = false |
| |
| func getReader(t *testing.T, name string) (r io.Reader) { |
| dir := os.Getenv("PN_INTEROP_DIR") |
| if dir == "" { |
| if !skipped { |
| skipped = true // Don't keep repeating |
| t.Skip("no PN_INTEROP_DIR in environment") |
| } else { |
| t.SkipNow() |
| } |
| } |
| r, err := os.Open(dir + "/" + name + ".amqp") |
| if err != nil { |
| t.Fatalf("can't open %#v: %v", name, err) |
| } |
| return |
| } |
| |
| func remaining(d *Decoder) string { |
| remainder, _ := ioutil.ReadAll(io.MultiReader(d.Buffered(), d.reader)) |
| return string(remainder) |
| } |
| |
| // checkDecode: want is the expected value, gotPtr is a pointer to a |
| // instance of the same type for Decode. |
| func checkDecode(d *Decoder, want interface{}, gotPtr interface{}, t *testing.T) { |
| |
| if err := d.Decode(gotPtr); err != nil { |
| t.Error("Decode failed", err) |
| return |
| } |
| got := reflect.ValueOf(gotPtr).Elem().Interface() |
| if err := test.Differ(want, got); err != nil { |
| t.Error("Decode bad value:", err) |
| return |
| } |
| |
| // Try round trip encoding |
| bytes, err := Marshal(want, nil) |
| if err != nil { |
| t.Error("Marshal failed", err) |
| return |
| } |
| n, err := Unmarshal(bytes, gotPtr) |
| if err != nil { |
| t.Error("Unmarshal failed", err) |
| return |
| } |
| err = test.Differ(n, len(bytes)) |
| if err != nil { |
| t.Error("Bad unmarshal length", err) |
| return |
| } |
| got = reflect.ValueOf(gotPtr).Elem().Interface() |
| if err = test.Differ(want, got); err != nil { |
| t.Error("Bad unmarshal value", err) |
| return |
| } |
| } |
| |
| func TestUnmarshal(t *testing.T) { |
| bytes, err := ioutil.ReadAll(getReader(t, "strings")) |
| if err != nil { |
| t.Error(err) |
| } |
| for _, want := range []string{"abc\000defg", "abcdefg", "abcdefg", "", "", ""} { |
| var got string |
| n, err := Unmarshal(bytes, &got) |
| if err != nil { |
| t.Error(err) |
| } |
| if want != got { |
| t.Errorf("%#v != %#v", want, got) |
| } |
| bytes = bytes[n:] |
| } |
| } |
| |
| func TestPrimitivesExact(t *testing.T) { |
| d := NewDecoder(getReader(t, "primitives")) |
| // Decoding into exact types |
| var b bool |
| checkDecode(d, true, &b, t) |
| checkDecode(d, false, &b, t) |
| var u8 uint8 |
| checkDecode(d, uint8(42), &u8, t) |
| var u16 uint16 |
| checkDecode(d, uint16(42), &u16, t) |
| var i16 int16 |
| checkDecode(d, int16(-42), &i16, t) |
| var u32 uint32 |
| checkDecode(d, uint32(12345), &u32, t) |
| var i32 int32 |
| checkDecode(d, int32(-12345), &i32, t) |
| var u64 uint64 |
| checkDecode(d, uint64(12345), &u64, t) |
| var i64 int64 |
| checkDecode(d, int64(-12345), &i64, t) |
| var f32 float32 |
| checkDecode(d, float32(0.125), &f32, t) |
| var f64 float64 |
| checkDecode(d, float64(0.125), &f64, t) |
| } |
| |
| func TestPrimitivesCompatible(t *testing.T) { |
| d := NewDecoder(getReader(t, "primitives")) |
| // Decoding into compatible types |
| var b bool |
| var i int |
| var u uint |
| var f float64 |
| checkDecode(d, true, &b, t) |
| checkDecode(d, false, &b, t) |
| checkDecode(d, uint(42), &u, t) |
| checkDecode(d, uint(42), &u, t) |
| checkDecode(d, -42, &i, t) |
| checkDecode(d, uint(12345), &u, t) |
| checkDecode(d, -12345, &i, t) |
| checkDecode(d, uint(12345), &u, t) |
| checkDecode(d, -12345, &i, t) |
| checkDecode(d, 0.125, &f, t) |
| checkDecode(d, 0.125, &f, t) |
| } |
| |
| // checkDecodeValue: want is the expected value, decode into a reflect.Value |
| func checkDecodeInterface(d *Decoder, want interface{}, t *testing.T) { |
| |
| var got, got2 interface{} |
| if err := d.Decode(&got); err != nil { |
| t.Error("Decode failed", err) |
| return |
| } |
| if err := test.Differ(want, got); err != nil { |
| t.Error(err) |
| return |
| } |
| // Try round trip encoding |
| bytes, err := Marshal(got, nil) |
| if err != nil { |
| t.Error(err) |
| return |
| } |
| n, err := Unmarshal(bytes, &got2) |
| if err != nil { |
| t.Error(err) |
| return |
| } |
| if err := test.Differ(n, len(bytes)); err != nil { |
| t.Error(err) |
| return |
| } |
| if err := test.Differ(want, got2); err != nil { |
| t.Error(err) |
| return |
| } |
| } |
| |
| func TestPrimitivesInterface(t *testing.T) { |
| d := NewDecoder(getReader(t, "primitives")) |
| checkDecodeInterface(d, true, t) |
| checkDecodeInterface(d, false, t) |
| checkDecodeInterface(d, uint8(42), t) |
| checkDecodeInterface(d, uint16(42), t) |
| checkDecodeInterface(d, int16(-42), t) |
| checkDecodeInterface(d, uint32(12345), t) |
| checkDecodeInterface(d, int32(-12345), t) |
| checkDecodeInterface(d, uint64(12345), t) |
| checkDecodeInterface(d, int64(-12345), t) |
| checkDecodeInterface(d, float32(0.125), t) |
| checkDecodeInterface(d, float64(0.125), t) |
| } |
| |
| func TestStrings(t *testing.T) { |
| d := NewDecoder(getReader(t, "strings")) |
| // Test decoding as plain Go strings |
| for _, want := range []string{"abc\000defg", "abcdefg", "abcdefg", "", "", ""} { |
| var got string |
| checkDecode(d, want, &got, t) |
| } |
| remains := remaining(d) |
| if remains != "" { |
| t.Errorf("leftover: %s", remains) |
| } |
| |
| // Test decoding as specific string types |
| d = NewDecoder(getReader(t, "strings")) |
| var bytes []byte |
| var str, sym string |
| checkDecode(d, []byte("abc\000defg"), &bytes, t) |
| checkDecode(d, "abcdefg", &str, t) |
| checkDecode(d, "abcdefg", &sym, t) |
| checkDecode(d, make([]byte, 0), &bytes, t) |
| checkDecode(d, "", &str, t) |
| checkDecode(d, "", &sym, t) |
| remains = remaining(d) |
| if remains != "" { |
| t.Fatalf("leftover: %s", remains) |
| } |
| |
| // Test some error handling |
| d = NewDecoder(getReader(t, "strings")) |
| var s string |
| err := d.Decode(s) |
| if err == nil { |
| t.Fatal("Expected error") |
| } |
| if !strings.Contains(err.Error(), "not a pointer") { |
| t.Error(err) |
| } |
| var i int |
| err = d.Decode(&i) |
| if !strings.Contains(err.Error(), "cannot unmarshal") { |
| t.Error(err) |
| } |
| _, err = Unmarshal([]byte{}, nil) |
| test.ErrorIf(t, test.Differ(err, EndOfData)) |
| _, err = Unmarshal([]byte("foobar"), nil) |
| if !strings.Contains(err.Error(), "invalid-argument") { |
| t.Error(err) |
| } |
| } |
| |
| func TestEncodeDecode(t *testing.T) { |
| type data struct { |
| s string |
| i int |
| u8 uint8 |
| b bool |
| f float32 |
| v interface{} |
| } |
| |
| in := data{"foo", 42, 9, true, 1.234, "thing"} |
| |
| buf := bytes.Buffer{} |
| e := NewEncoder(&buf) |
| if err := e.Encode(in.s); err != nil { |
| t.Error(err) |
| } |
| if err := e.Encode(in.i); err != nil { |
| t.Error(err) |
| } |
| if err := e.Encode(in.u8); err != nil { |
| t.Error(err) |
| } |
| if err := e.Encode(in.b); err != nil { |
| t.Error(err) |
| } |
| if err := e.Encode(in.f); err != nil { |
| t.Error(err) |
| } |
| if err := e.Encode(in.v); err != nil { |
| t.Error(err) |
| } |
| |
| var out data |
| d := NewDecoder(&buf) |
| if err := d.Decode(&out.s); err != nil { |
| t.Error(err) |
| } |
| if err := d.Decode(&out.i); err != nil { |
| t.Error(err) |
| } |
| if err := d.Decode(&out.u8); err != nil { |
| t.Error(err) |
| } |
| if err := d.Decode(&out.b); err != nil { |
| t.Error(err) |
| } |
| if err := d.Decode(&out.f); err != nil { |
| t.Error(err) |
| } |
| if err := d.Decode(&out.v); err != nil { |
| t.Error(err) |
| } |
| |
| if err := test.Differ(in, out); err != nil { |
| t.Error(err) |
| } |
| } |
| |
| func TestMap(t *testing.T) { |
| d := NewDecoder(getReader(t, "maps")) |
| |
| // Generic map |
| var m Map |
| checkDecode(d, Map{"one": int32(1), "two": int32(2), "three": int32(3)}, &m, t) |
| |
| // Interface as map |
| var i interface{} |
| checkDecode(d, Map{int32(1): "one", int32(2): "two", int32(3): "three"}, &i, t) |
| |
| d = NewDecoder(getReader(t, "maps")) |
| // Specific typed map |
| var m2 map[string]int |
| checkDecode(d, map[string]int{"one": 1, "two": 2, "three": 3}, &m2, t) |
| |
| // Nested map |
| m = Map{int64(1): "one", "two": int32(2), true: Map{uint8(1): true, uint8(2): false}} |
| bytes, err := Marshal(m, nil) |
| if err != nil { |
| t.Fatal(err) |
| } |
| _, err = Unmarshal(bytes, &i) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if err = test.Differ(m, i); err != nil { |
| t.Fatal(err) |
| } |
| } |
| |
| func TestList(t *testing.T) { |
| d := NewDecoder(getReader(t, "lists")) |
| var l List |
| checkDecode(d, List{int32(32), "foo", true}, &l, t) |
| checkDecode(d, List{}, &l, t) |
| } |
| |
| // TODO aconway 2015-09-08: the message.amqp file seems to be incorrectly coded as |
| // as an AMQP string *inside* an AMQP binary?? Skip the test for now. |
| func TODO_TestMessage(t *testing.T) { |
| bytes, err := ioutil.ReadAll(getReader(t, "message")) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| m, err := DecodeMessage(bytes) |
| if err != nil { |
| t.Fatal(err) |
| } else { |
| if err = test.Differ(m.Body(), "hello"); err != nil { |
| t.Error(err) |
| } |
| } |
| |
| m2 := NewMessageWith("hello") |
| bytes2, err := m2.Encode(nil) |
| if err != nil { |
| t.Error(err) |
| } else { |
| if err = test.Differ(bytes, bytes2); err != nil { |
| t.Error(err) |
| } |
| } |
| } |
| |
| // TODO aconway 2015-03-13: finish the full interop test |