|  | // run | 
|  |  | 
|  | // Copyright 2019 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | // short-circuiting interface-to-concrete comparisons | 
|  | // will not miss panics | 
|  |  | 
|  | package main | 
|  |  | 
|  | import ( | 
|  | "log" | 
|  | "strings" | 
|  | ) | 
|  |  | 
|  | func main() { | 
|  | var ( | 
|  | x interface{} | 
|  | p *int | 
|  | s []int | 
|  | l *interface{} | 
|  | r []*int | 
|  | ) | 
|  | tests := []struct { | 
|  | name   string | 
|  | errStr string | 
|  | f      func() | 
|  | }{ | 
|  | {"switch case", "", func() { | 
|  | switch x { | 
|  | case x.(*int): | 
|  | } | 
|  | }}, | 
|  | {"interface conversion", "", func() { _ = x == x.(error) }}, | 
|  | {"type assertion", "", func() { _ = x == x.(*int) }}, | 
|  | {"out of bounds", "", func() { _ = x == s[1] }}, | 
|  | {"nil pointer dereference #1", "", func() { _ = x == *p }}, | 
|  | {"nil pointer dereference #2", "nil pointer dereference", func() { _ = *l == r[0] }}, | 
|  | } | 
|  |  | 
|  | for _, tc := range tests { | 
|  | testFuncShouldPanic(tc.name, tc.errStr, tc.f) | 
|  | } | 
|  | } | 
|  |  | 
|  | func testFuncShouldPanic(name, errStr string, f func()) { | 
|  | defer func() { | 
|  | e := recover() | 
|  | if e == nil { | 
|  | log.Fatalf("%s: comparison did not panic\n", name) | 
|  | } | 
|  | if errStr != "" { | 
|  | if !strings.Contains(e.(error).Error(), errStr) { | 
|  | log.Fatalf("%s: wrong panic message\n", name) | 
|  | } | 
|  | } | 
|  | }() | 
|  | f() | 
|  | } |