Brad Fitzpatrick | 5194744 | 2016-03-01 22:57:46 +0000 | [diff] [blame] | 1 | // Copyright 2011 The Go Authors. All rights reserved. |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | package reflect_test |
| 6 | |
| 7 | import ( |
| 8 | "bytes" |
| 9 | "go/ast" |
| 10 | "io" |
| 11 | . "reflect" |
| 12 | "testing" |
| 13 | "unsafe" |
| 14 | ) |
| 15 | |
| 16 | type MyBuffer bytes.Buffer |
| 17 | |
| 18 | func TestImplicitMapConversion(t *testing.T) { |
| 19 | // Test implicit conversions in MapIndex and SetMapIndex. |
| 20 | { |
| 21 | // direct |
| 22 | m := make(map[int]int) |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 23 | mv := ValueOf(m) |
| 24 | mv.SetMapIndex(ValueOf(1), ValueOf(2)) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 25 | x, ok := m[1] |
| 26 | if x != 2 { |
| 27 | t.Errorf("#1 after SetMapIndex(1,2): %d, %t (map=%v)", x, ok, m) |
| 28 | } |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 29 | if n := mv.MapIndex(ValueOf(1)).Interface().(int); n != 2 { |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 30 | t.Errorf("#1 MapIndex(1) = %d", n) |
| 31 | } |
| 32 | } |
| 33 | { |
| 34 | // convert interface key |
| 35 | m := make(map[interface{}]int) |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 36 | mv := ValueOf(m) |
| 37 | mv.SetMapIndex(ValueOf(1), ValueOf(2)) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 38 | x, ok := m[1] |
| 39 | if x != 2 { |
| 40 | t.Errorf("#2 after SetMapIndex(1,2): %d, %t (map=%v)", x, ok, m) |
| 41 | } |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 42 | if n := mv.MapIndex(ValueOf(1)).Interface().(int); n != 2 { |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 43 | t.Errorf("#2 MapIndex(1) = %d", n) |
| 44 | } |
| 45 | } |
| 46 | { |
| 47 | // convert interface value |
| 48 | m := make(map[int]interface{}) |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 49 | mv := ValueOf(m) |
| 50 | mv.SetMapIndex(ValueOf(1), ValueOf(2)) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 51 | x, ok := m[1] |
| 52 | if x != 2 { |
| 53 | t.Errorf("#3 after SetMapIndex(1,2): %d, %t (map=%v)", x, ok, m) |
| 54 | } |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 55 | if n := mv.MapIndex(ValueOf(1)).Interface().(int); n != 2 { |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 56 | t.Errorf("#3 MapIndex(1) = %d", n) |
| 57 | } |
| 58 | } |
| 59 | { |
| 60 | // convert both interface key and interface value |
| 61 | m := make(map[interface{}]interface{}) |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 62 | mv := ValueOf(m) |
| 63 | mv.SetMapIndex(ValueOf(1), ValueOf(2)) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 64 | x, ok := m[1] |
| 65 | if x != 2 { |
| 66 | t.Errorf("#4 after SetMapIndex(1,2): %d, %t (map=%v)", x, ok, m) |
| 67 | } |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 68 | if n := mv.MapIndex(ValueOf(1)).Interface().(int); n != 2 { |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 69 | t.Errorf("#4 MapIndex(1) = %d", n) |
| 70 | } |
| 71 | } |
| 72 | { |
| 73 | // convert both, with non-empty interfaces |
| 74 | m := make(map[io.Reader]io.Writer) |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 75 | mv := ValueOf(m) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 76 | b1 := new(bytes.Buffer) |
| 77 | b2 := new(bytes.Buffer) |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 78 | mv.SetMapIndex(ValueOf(b1), ValueOf(b2)) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 79 | x, ok := m[b1] |
| 80 | if x != b2 { |
| 81 | t.Errorf("#5 after SetMapIndex(b1, b2): %p (!= %p), %t (map=%v)", x, b2, ok, m) |
| 82 | } |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 83 | if p := mv.MapIndex(ValueOf(b1)).Elem().Pointer(); p != uintptr(unsafe.Pointer(b2)) { |
Rob Pike | 1bf66f0 | 2013-02-28 11:33:08 -0800 | [diff] [blame] | 84 | t.Errorf("#5 MapIndex(b1) = %#x want %p", p, b2) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 85 | } |
| 86 | } |
| 87 | { |
Robert Griesemer | 465b9c3 | 2012-10-30 13:38:01 -0700 | [diff] [blame] | 88 | // convert channel direction |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 89 | m := make(map[<-chan int]chan int) |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 90 | mv := ValueOf(m) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 91 | c1 := make(chan int) |
| 92 | c2 := make(chan int) |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 93 | mv.SetMapIndex(ValueOf(c1), ValueOf(c2)) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 94 | x, ok := m[c1] |
| 95 | if x != c2 { |
| 96 | t.Errorf("#6 after SetMapIndex(c1, c2): %p (!= %p), %t (map=%v)", x, c2, ok, m) |
| 97 | } |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 98 | if p := mv.MapIndex(ValueOf(c1)).Pointer(); p != ValueOf(c2).Pointer() { |
Rob Pike | 1bf66f0 | 2013-02-28 11:33:08 -0800 | [diff] [blame] | 99 | t.Errorf("#6 MapIndex(c1) = %#x want %p", p, c2) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 100 | } |
| 101 | } |
| 102 | { |
| 103 | // convert identical underlying types |
| 104 | // TODO(rsc): Should be able to define MyBuffer here. |
| 105 | // 6l prints very strange messages about .this.Bytes etc |
| 106 | // when we do that though, so MyBuffer is defined |
| 107 | // at top level. |
| 108 | m := make(map[*MyBuffer]*bytes.Buffer) |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 109 | mv := ValueOf(m) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 110 | b1 := new(MyBuffer) |
| 111 | b2 := new(bytes.Buffer) |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 112 | mv.SetMapIndex(ValueOf(b1), ValueOf(b2)) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 113 | x, ok := m[b1] |
| 114 | if x != b2 { |
| 115 | t.Errorf("#7 after SetMapIndex(b1, b2): %p (!= %p), %t (map=%v)", x, b2, ok, m) |
| 116 | } |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 117 | if p := mv.MapIndex(ValueOf(b1)).Pointer(); p != uintptr(unsafe.Pointer(b2)) { |
Rob Pike | 1bf66f0 | 2013-02-28 11:33:08 -0800 | [diff] [blame] | 118 | t.Errorf("#7 MapIndex(b1) = %#x want %p", p, b2) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 119 | } |
| 120 | } |
| 121 | |
| 122 | } |
| 123 | |
| 124 | func TestImplicitSetConversion(t *testing.T) { |
| 125 | // Assume TestImplicitMapConversion covered the basics. |
| 126 | // Just make sure conversions are being applied at all. |
| 127 | var r io.Reader |
| 128 | b := new(bytes.Buffer) |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 129 | rv := ValueOf(&r).Elem() |
| 130 | rv.Set(ValueOf(b)) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 131 | if r != b { |
| 132 | t.Errorf("after Set: r=%T(%v)", r, r) |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | func TestImplicitSendConversion(t *testing.T) { |
| 137 | c := make(chan io.Reader, 10) |
| 138 | b := new(bytes.Buffer) |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 139 | ValueOf(c).Send(ValueOf(b)) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 140 | if bb := <-c; bb != b { |
| 141 | t.Errorf("Received %p != %p", bb, b) |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | func TestImplicitCallConversion(t *testing.T) { |
| 146 | // Arguments must be assignable to parameter types. |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 147 | fv := ValueOf(io.WriteString) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 148 | b := new(bytes.Buffer) |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 149 | fv.Call([]Value{ValueOf(b), ValueOf("hello world")}) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 150 | if b.String() != "hello world" { |
| 151 | t.Errorf("After call: string=%q want %q", b.String(), "hello world") |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | func TestImplicitAppendConversion(t *testing.T) { |
| 156 | // Arguments must be assignable to the slice's element type. |
| 157 | s := []io.Reader{} |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 158 | sv := ValueOf(&s).Elem() |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 159 | b := new(bytes.Buffer) |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 160 | sv.Set(Append(sv, ValueOf(b))) |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 161 | if len(s) != 1 || s[0] != b { |
| 162 | t.Errorf("after append: s=%v want [%p]", s, b) |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | var implementsTests = []struct { |
| 167 | x interface{} |
| 168 | t interface{} |
| 169 | b bool |
| 170 | }{ |
| 171 | {new(*bytes.Buffer), new(io.Reader), true}, |
| 172 | {new(bytes.Buffer), new(io.Reader), false}, |
| 173 | {new(*bytes.Buffer), new(io.ReaderAt), false}, |
| 174 | {new(*ast.Ident), new(ast.Expr), true}, |
| 175 | } |
| 176 | |
| 177 | func TestImplements(t *testing.T) { |
| 178 | for _, tt := range implementsTests { |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 179 | xv := TypeOf(tt.x).Elem() |
| 180 | xt := TypeOf(tt.t).Elem() |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 181 | if b := xv.Implements(xt); b != tt.b { |
| 182 | t.Errorf("(%s).Implements(%s) = %v, want %v", xv.String(), xt.String(), b, tt.b) |
| 183 | } |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | var assignableTests = []struct { |
| 188 | x interface{} |
| 189 | t interface{} |
| 190 | b bool |
| 191 | }{ |
| 192 | {new(chan int), new(<-chan int), true}, |
| 193 | {new(<-chan int), new(chan int), false}, |
| 194 | {new(*int), new(IntPtr), true}, |
| 195 | {new(IntPtr), new(*int), true}, |
| 196 | {new(IntPtr), new(IntPtr1), false}, |
David Crawshaw | 69285a8 | 2016-03-04 14:53:26 -0500 | [diff] [blame] | 197 | {new(Ch), new(<-chan interface{}), true}, |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 198 | // test runs implementsTests too |
| 199 | } |
| 200 | |
| 201 | type IntPtr *int |
| 202 | type IntPtr1 *int |
David Crawshaw | 69285a8 | 2016-03-04 14:53:26 -0500 | [diff] [blame] | 203 | type Ch <-chan interface{} |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 204 | |
| 205 | func TestAssignableTo(t *testing.T) { |
| 206 | for _, tt := range append(assignableTests, implementsTests...) { |
Russ Cox | 0e2bb62 | 2011-04-25 13:39:16 -0400 | [diff] [blame] | 207 | xv := TypeOf(tt.x).Elem() |
| 208 | xt := TypeOf(tt.t).Elem() |
Russ Cox | e1ee3b5 | 2011-04-20 16:24:45 -0400 | [diff] [blame] | 209 | if b := xv.AssignableTo(xt); b != tt.b { |
| 210 | t.Errorf("(%s).AssignableTo(%s) = %v, want %v", xv.String(), xt.String(), b, tt.b) |
| 211 | } |
| 212 | } |
| 213 | } |