| // 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() | |
| } |