1*88d15eacSSasha Smundak// Copyright 2017, The Go Authors. All rights reserved. 2*88d15eacSSasha Smundak// Use of this source code is governed by a BSD-style 3*88d15eacSSasha Smundak// license that can be found in the LICENSE file. 4*88d15eacSSasha Smundak 5*88d15eacSSasha Smundakpackage cmp_test 6*88d15eacSSasha Smundak 7*88d15eacSSasha Smundakimport ( 8*88d15eacSSasha Smundak "fmt" 9*88d15eacSSasha Smundak "math" 10*88d15eacSSasha Smundak "net" 11*88d15eacSSasha Smundak "reflect" 12*88d15eacSSasha Smundak "sort" 13*88d15eacSSasha Smundak "strings" 14*88d15eacSSasha Smundak "time" 15*88d15eacSSasha Smundak 16*88d15eacSSasha Smundak "github.com/google/go-cmp/cmp" 17*88d15eacSSasha Smundak) 18*88d15eacSSasha Smundak 19*88d15eacSSasha Smundak// TODO: Re-write these examples in terms of how you actually use the 20*88d15eacSSasha Smundak// fundamental options and filters and not in terms of what cool things you can 21*88d15eacSSasha Smundak// do with them since that overlaps with cmp/cmpopts. 22*88d15eacSSasha Smundak 23*88d15eacSSasha Smundak// Use Diff to print out a human-readable report of differences for tests 24*88d15eacSSasha Smundak// comparing nested or structured data. 25*88d15eacSSasha Smundakfunc ExampleDiff_testing() { 26*88d15eacSSasha Smundak // Let got be the hypothetical value obtained from some logic under test 27*88d15eacSSasha Smundak // and want be the expected golden data. 28*88d15eacSSasha Smundak got, want := MakeGatewayInfo() 29*88d15eacSSasha Smundak 30*88d15eacSSasha Smundak if diff := cmp.Diff(want, got); diff != "" { 31*88d15eacSSasha Smundak t.Errorf("MakeGatewayInfo() mismatch (-want +got):\n%s", diff) 32*88d15eacSSasha Smundak } 33*88d15eacSSasha Smundak 34*88d15eacSSasha Smundak // Output: 35*88d15eacSSasha Smundak // MakeGatewayInfo() mismatch (-want +got): 36*88d15eacSSasha Smundak // cmp_test.Gateway{ 37*88d15eacSSasha Smundak // SSID: "CoffeeShopWiFi", 38*88d15eacSSasha Smundak // - IPAddress: s"192.168.0.2", 39*88d15eacSSasha Smundak // + IPAddress: s"192.168.0.1", 40*88d15eacSSasha Smundak // NetMask: s"ffff0000", 41*88d15eacSSasha Smundak // Clients: []cmp_test.Client{ 42*88d15eacSSasha Smundak // ... // 2 identical elements 43*88d15eacSSasha Smundak // {Hostname: "macchiato", IPAddress: s"192.168.0.153", LastSeen: s"2009-11-10 23:39:43 +0000 UTC"}, 44*88d15eacSSasha Smundak // {Hostname: "espresso", IPAddress: s"192.168.0.121"}, 45*88d15eacSSasha Smundak // { 46*88d15eacSSasha Smundak // Hostname: "latte", 47*88d15eacSSasha Smundak // - IPAddress: s"192.168.0.221", 48*88d15eacSSasha Smundak // + IPAddress: s"192.168.0.219", 49*88d15eacSSasha Smundak // LastSeen: s"2009-11-10 23:00:23 +0000 UTC", 50*88d15eacSSasha Smundak // }, 51*88d15eacSSasha Smundak // + { 52*88d15eacSSasha Smundak // + Hostname: "americano", 53*88d15eacSSasha Smundak // + IPAddress: s"192.168.0.188", 54*88d15eacSSasha Smundak // + LastSeen: s"2009-11-10 23:03:05 +0000 UTC", 55*88d15eacSSasha Smundak // + }, 56*88d15eacSSasha Smundak // }, 57*88d15eacSSasha Smundak // } 58*88d15eacSSasha Smundak} 59*88d15eacSSasha Smundak 60*88d15eacSSasha Smundak// Approximate equality for floats can be handled by defining a custom 61*88d15eacSSasha Smundak// comparer on floats that determines two values to be equal if they are within 62*88d15eacSSasha Smundak// some range of each other. 63*88d15eacSSasha Smundak// 64*88d15eacSSasha Smundak// This example is for demonstrative purposes; use cmpopts.EquateApprox instead. 65*88d15eacSSasha Smundakfunc ExampleOption_approximateFloats() { 66*88d15eacSSasha Smundak // This Comparer only operates on float64. 67*88d15eacSSasha Smundak // To handle float32s, either define a similar function for that type 68*88d15eacSSasha Smundak // or use a Transformer to convert float32s into float64s. 69*88d15eacSSasha Smundak opt := cmp.Comparer(func(x, y float64) bool { 70*88d15eacSSasha Smundak delta := math.Abs(x - y) 71*88d15eacSSasha Smundak mean := math.Abs(x+y) / 2.0 72*88d15eacSSasha Smundak return delta/mean < 0.00001 73*88d15eacSSasha Smundak }) 74*88d15eacSSasha Smundak 75*88d15eacSSasha Smundak x := []float64{1.0, 1.1, 1.2, math.Pi} 76*88d15eacSSasha Smundak y := []float64{1.0, 1.1, 1.2, 3.14159265359} // Accurate enough to Pi 77*88d15eacSSasha Smundak z := []float64{1.0, 1.1, 1.2, 3.1415} // Diverges too far from Pi 78*88d15eacSSasha Smundak 79*88d15eacSSasha Smundak fmt.Println(cmp.Equal(x, y, opt)) 80*88d15eacSSasha Smundak fmt.Println(cmp.Equal(y, z, opt)) 81*88d15eacSSasha Smundak fmt.Println(cmp.Equal(z, x, opt)) 82*88d15eacSSasha Smundak 83*88d15eacSSasha Smundak // Output: 84*88d15eacSSasha Smundak // true 85*88d15eacSSasha Smundak // false 86*88d15eacSSasha Smundak // false 87*88d15eacSSasha Smundak} 88*88d15eacSSasha Smundak 89*88d15eacSSasha Smundak// Normal floating-point arithmetic defines == to be false when comparing 90*88d15eacSSasha Smundak// NaN with itself. In certain cases, this is not the desired property. 91*88d15eacSSasha Smundak// 92*88d15eacSSasha Smundak// This example is for demonstrative purposes; use cmpopts.EquateNaNs instead. 93*88d15eacSSasha Smundakfunc ExampleOption_equalNaNs() { 94*88d15eacSSasha Smundak // This Comparer only operates on float64. 95*88d15eacSSasha Smundak // To handle float32s, either define a similar function for that type 96*88d15eacSSasha Smundak // or use a Transformer to convert float32s into float64s. 97*88d15eacSSasha Smundak opt := cmp.Comparer(func(x, y float64) bool { 98*88d15eacSSasha Smundak return (math.IsNaN(x) && math.IsNaN(y)) || x == y 99*88d15eacSSasha Smundak }) 100*88d15eacSSasha Smundak 101*88d15eacSSasha Smundak x := []float64{1.0, math.NaN(), math.E, 0.0} 102*88d15eacSSasha Smundak y := []float64{1.0, math.NaN(), math.E, 0.0} 103*88d15eacSSasha Smundak z := []float64{1.0, math.NaN(), math.Pi, 0.0} // Pi constant instead of E 104*88d15eacSSasha Smundak 105*88d15eacSSasha Smundak fmt.Println(cmp.Equal(x, y, opt)) 106*88d15eacSSasha Smundak fmt.Println(cmp.Equal(y, z, opt)) 107*88d15eacSSasha Smundak fmt.Println(cmp.Equal(z, x, opt)) 108*88d15eacSSasha Smundak 109*88d15eacSSasha Smundak // Output: 110*88d15eacSSasha Smundak // true 111*88d15eacSSasha Smundak // false 112*88d15eacSSasha Smundak // false 113*88d15eacSSasha Smundak} 114*88d15eacSSasha Smundak 115*88d15eacSSasha Smundak// To have floating-point comparisons combine both properties of NaN being 116*88d15eacSSasha Smundak// equal to itself and also approximate equality of values, filters are needed 117*88d15eacSSasha Smundak// to restrict the scope of the comparison so that they are composable. 118*88d15eacSSasha Smundak// 119*88d15eacSSasha Smundak// This example is for demonstrative purposes; 120*88d15eacSSasha Smundak// use cmpopts.EquateNaNs and cmpopts.EquateApprox instead. 121*88d15eacSSasha Smundakfunc ExampleOption_equalNaNsAndApproximateFloats() { 122*88d15eacSSasha Smundak alwaysEqual := cmp.Comparer(func(_, _ interface{}) bool { return true }) 123*88d15eacSSasha Smundak 124*88d15eacSSasha Smundak opts := cmp.Options{ 125*88d15eacSSasha Smundak // This option declares that a float64 comparison is equal only if 126*88d15eacSSasha Smundak // both inputs are NaN. 127*88d15eacSSasha Smundak cmp.FilterValues(func(x, y float64) bool { 128*88d15eacSSasha Smundak return math.IsNaN(x) && math.IsNaN(y) 129*88d15eacSSasha Smundak }, alwaysEqual), 130*88d15eacSSasha Smundak 131*88d15eacSSasha Smundak // This option declares approximate equality on float64s only if 132*88d15eacSSasha Smundak // both inputs are not NaN. 133*88d15eacSSasha Smundak cmp.FilterValues(func(x, y float64) bool { 134*88d15eacSSasha Smundak return !math.IsNaN(x) && !math.IsNaN(y) 135*88d15eacSSasha Smundak }, cmp.Comparer(func(x, y float64) bool { 136*88d15eacSSasha Smundak delta := math.Abs(x - y) 137*88d15eacSSasha Smundak mean := math.Abs(x+y) / 2.0 138*88d15eacSSasha Smundak return delta/mean < 0.00001 139*88d15eacSSasha Smundak })), 140*88d15eacSSasha Smundak } 141*88d15eacSSasha Smundak 142*88d15eacSSasha Smundak x := []float64{math.NaN(), 1.0, 1.1, 1.2, math.Pi} 143*88d15eacSSasha Smundak y := []float64{math.NaN(), 1.0, 1.1, 1.2, 3.14159265359} // Accurate enough to Pi 144*88d15eacSSasha Smundak z := []float64{math.NaN(), 1.0, 1.1, 1.2, 3.1415} // Diverges too far from Pi 145*88d15eacSSasha Smundak 146*88d15eacSSasha Smundak fmt.Println(cmp.Equal(x, y, opts)) 147*88d15eacSSasha Smundak fmt.Println(cmp.Equal(y, z, opts)) 148*88d15eacSSasha Smundak fmt.Println(cmp.Equal(z, x, opts)) 149*88d15eacSSasha Smundak 150*88d15eacSSasha Smundak // Output: 151*88d15eacSSasha Smundak // true 152*88d15eacSSasha Smundak // false 153*88d15eacSSasha Smundak // false 154*88d15eacSSasha Smundak} 155*88d15eacSSasha Smundak 156*88d15eacSSasha Smundak// Sometimes, an empty map or slice is considered equal to an allocated one 157*88d15eacSSasha Smundak// of zero length. 158*88d15eacSSasha Smundak// 159*88d15eacSSasha Smundak// This example is for demonstrative purposes; use cmpopts.EquateEmpty instead. 160*88d15eacSSasha Smundakfunc ExampleOption_equalEmpty() { 161*88d15eacSSasha Smundak alwaysEqual := cmp.Comparer(func(_, _ interface{}) bool { return true }) 162*88d15eacSSasha Smundak 163*88d15eacSSasha Smundak // This option handles slices and maps of any type. 164*88d15eacSSasha Smundak opt := cmp.FilterValues(func(x, y interface{}) bool { 165*88d15eacSSasha Smundak vx, vy := reflect.ValueOf(x), reflect.ValueOf(y) 166*88d15eacSSasha Smundak return (vx.IsValid() && vy.IsValid() && vx.Type() == vy.Type()) && 167*88d15eacSSasha Smundak (vx.Kind() == reflect.Slice || vx.Kind() == reflect.Map) && 168*88d15eacSSasha Smundak (vx.Len() == 0 && vy.Len() == 0) 169*88d15eacSSasha Smundak }, alwaysEqual) 170*88d15eacSSasha Smundak 171*88d15eacSSasha Smundak type S struct { 172*88d15eacSSasha Smundak A []int 173*88d15eacSSasha Smundak B map[string]bool 174*88d15eacSSasha Smundak } 175*88d15eacSSasha Smundak x := S{nil, make(map[string]bool, 100)} 176*88d15eacSSasha Smundak y := S{make([]int, 0, 200), nil} 177*88d15eacSSasha Smundak z := S{[]int{0}, nil} // []int has a single element (i.e., not empty) 178*88d15eacSSasha Smundak 179*88d15eacSSasha Smundak fmt.Println(cmp.Equal(x, y, opt)) 180*88d15eacSSasha Smundak fmt.Println(cmp.Equal(y, z, opt)) 181*88d15eacSSasha Smundak fmt.Println(cmp.Equal(z, x, opt)) 182*88d15eacSSasha Smundak 183*88d15eacSSasha Smundak // Output: 184*88d15eacSSasha Smundak // true 185*88d15eacSSasha Smundak // false 186*88d15eacSSasha Smundak // false 187*88d15eacSSasha Smundak} 188*88d15eacSSasha Smundak 189*88d15eacSSasha Smundak// Two slices may be considered equal if they have the same elements, 190*88d15eacSSasha Smundak// regardless of the order that they appear in. Transformations can be used 191*88d15eacSSasha Smundak// to sort the slice. 192*88d15eacSSasha Smundak// 193*88d15eacSSasha Smundak// This example is for demonstrative purposes; use cmpopts.SortSlices instead. 194*88d15eacSSasha Smundakfunc ExampleOption_sortedSlice() { 195*88d15eacSSasha Smundak // This Transformer sorts a []int. 196*88d15eacSSasha Smundak trans := cmp.Transformer("Sort", func(in []int) []int { 197*88d15eacSSasha Smundak out := append([]int(nil), in...) // Copy input to avoid mutating it 198*88d15eacSSasha Smundak sort.Ints(out) 199*88d15eacSSasha Smundak return out 200*88d15eacSSasha Smundak }) 201*88d15eacSSasha Smundak 202*88d15eacSSasha Smundak x := struct{ Ints []int }{[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}} 203*88d15eacSSasha Smundak y := struct{ Ints []int }{[]int{2, 8, 0, 9, 6, 1, 4, 7, 3, 5}} 204*88d15eacSSasha Smundak z := struct{ Ints []int }{[]int{0, 0, 1, 2, 3, 4, 5, 6, 7, 8}} 205*88d15eacSSasha Smundak 206*88d15eacSSasha Smundak fmt.Println(cmp.Equal(x, y, trans)) 207*88d15eacSSasha Smundak fmt.Println(cmp.Equal(y, z, trans)) 208*88d15eacSSasha Smundak fmt.Println(cmp.Equal(z, x, trans)) 209*88d15eacSSasha Smundak 210*88d15eacSSasha Smundak // Output: 211*88d15eacSSasha Smundak // true 212*88d15eacSSasha Smundak // false 213*88d15eacSSasha Smundak // false 214*88d15eacSSasha Smundak} 215*88d15eacSSasha Smundak 216*88d15eacSSasha Smundaktype otherString string 217*88d15eacSSasha Smundak 218*88d15eacSSasha Smundakfunc (x otherString) Equal(y otherString) bool { 219*88d15eacSSasha Smundak return strings.EqualFold(string(x), string(y)) 220*88d15eacSSasha Smundak} 221*88d15eacSSasha Smundak 222*88d15eacSSasha Smundak// If the Equal method defined on a type is not suitable, the type can be 223*88d15eacSSasha Smundak// dynamically transformed to be stripped of the Equal method (or any method 224*88d15eacSSasha Smundak// for that matter). 225*88d15eacSSasha Smundakfunc ExampleOption_avoidEqualMethod() { 226*88d15eacSSasha Smundak // Suppose otherString.Equal performs a case-insensitive equality, 227*88d15eacSSasha Smundak // which is too loose for our needs. 228*88d15eacSSasha Smundak // We can avoid the methods of otherString by declaring a new type. 229*88d15eacSSasha Smundak type myString otherString 230*88d15eacSSasha Smundak 231*88d15eacSSasha Smundak // This transformer converts otherString to myString, allowing Equal to use 232*88d15eacSSasha Smundak // other Options to determine equality. 233*88d15eacSSasha Smundak trans := cmp.Transformer("", func(in otherString) myString { 234*88d15eacSSasha Smundak return myString(in) 235*88d15eacSSasha Smundak }) 236*88d15eacSSasha Smundak 237*88d15eacSSasha Smundak x := []otherString{"foo", "bar", "baz"} 238*88d15eacSSasha Smundak y := []otherString{"fOO", "bAr", "Baz"} // Same as before, but with different case 239*88d15eacSSasha Smundak 240*88d15eacSSasha Smundak fmt.Println(cmp.Equal(x, y)) // Equal because of case-insensitivity 241*88d15eacSSasha Smundak fmt.Println(cmp.Equal(x, y, trans)) // Not equal because of more exact equality 242*88d15eacSSasha Smundak 243*88d15eacSSasha Smundak // Output: 244*88d15eacSSasha Smundak // true 245*88d15eacSSasha Smundak // false 246*88d15eacSSasha Smundak} 247*88d15eacSSasha Smundak 248*88d15eacSSasha Smundakfunc roundF64(z float64) float64 { 249*88d15eacSSasha Smundak if z < 0 { 250*88d15eacSSasha Smundak return math.Ceil(z - 0.5) 251*88d15eacSSasha Smundak } 252*88d15eacSSasha Smundak return math.Floor(z + 0.5) 253*88d15eacSSasha Smundak} 254*88d15eacSSasha Smundak 255*88d15eacSSasha Smundak// The complex numbers complex64 and complex128 can really just be decomposed 256*88d15eacSSasha Smundak// into a pair of float32 or float64 values. It would be convenient to be able 257*88d15eacSSasha Smundak// define only a single comparator on float64 and have float32, complex64, and 258*88d15eacSSasha Smundak// complex128 all be able to use that comparator. Transformations can be used 259*88d15eacSSasha Smundak// to handle this. 260*88d15eacSSasha Smundakfunc ExampleOption_transformComplex() { 261*88d15eacSSasha Smundak opts := []cmp.Option{ 262*88d15eacSSasha Smundak // This transformer decomposes complex128 into a pair of float64s. 263*88d15eacSSasha Smundak cmp.Transformer("T1", func(in complex128) (out struct{ Real, Imag float64 }) { 264*88d15eacSSasha Smundak out.Real, out.Imag = real(in), imag(in) 265*88d15eacSSasha Smundak return out 266*88d15eacSSasha Smundak }), 267*88d15eacSSasha Smundak // This transformer converts complex64 to complex128 to allow the 268*88d15eacSSasha Smundak // above transform to take effect. 269*88d15eacSSasha Smundak cmp.Transformer("T2", func(in complex64) complex128 { 270*88d15eacSSasha Smundak return complex128(in) 271*88d15eacSSasha Smundak }), 272*88d15eacSSasha Smundak // This transformer converts float32 to float64. 273*88d15eacSSasha Smundak cmp.Transformer("T3", func(in float32) float64 { 274*88d15eacSSasha Smundak return float64(in) 275*88d15eacSSasha Smundak }), 276*88d15eacSSasha Smundak // This equality function compares float64s as rounded integers. 277*88d15eacSSasha Smundak cmp.Comparer(func(x, y float64) bool { 278*88d15eacSSasha Smundak return roundF64(x) == roundF64(y) 279*88d15eacSSasha Smundak }), 280*88d15eacSSasha Smundak } 281*88d15eacSSasha Smundak 282*88d15eacSSasha Smundak x := []interface{}{ 283*88d15eacSSasha Smundak complex128(3.0), complex64(5.1 + 2.9i), float32(-1.2), float64(12.3), 284*88d15eacSSasha Smundak } 285*88d15eacSSasha Smundak y := []interface{}{ 286*88d15eacSSasha Smundak complex128(3.1), complex64(4.9 + 3.1i), float32(-1.3), float64(11.7), 287*88d15eacSSasha Smundak } 288*88d15eacSSasha Smundak z := []interface{}{ 289*88d15eacSSasha Smundak complex128(3.8), complex64(4.9 + 3.1i), float32(-1.3), float64(11.7), 290*88d15eacSSasha Smundak } 291*88d15eacSSasha Smundak 292*88d15eacSSasha Smundak fmt.Println(cmp.Equal(x, y, opts...)) 293*88d15eacSSasha Smundak fmt.Println(cmp.Equal(y, z, opts...)) 294*88d15eacSSasha Smundak fmt.Println(cmp.Equal(z, x, opts...)) 295*88d15eacSSasha Smundak 296*88d15eacSSasha Smundak // Output: 297*88d15eacSSasha Smundak // true 298*88d15eacSSasha Smundak // false 299*88d15eacSSasha Smundak // false 300*88d15eacSSasha Smundak} 301*88d15eacSSasha Smundak 302*88d15eacSSasha Smundaktype ( 303*88d15eacSSasha Smundak Gateway struct { 304*88d15eacSSasha Smundak SSID string 305*88d15eacSSasha Smundak IPAddress net.IP 306*88d15eacSSasha Smundak NetMask net.IPMask 307*88d15eacSSasha Smundak Clients []Client 308*88d15eacSSasha Smundak } 309*88d15eacSSasha Smundak Client struct { 310*88d15eacSSasha Smundak Hostname string 311*88d15eacSSasha Smundak IPAddress net.IP 312*88d15eacSSasha Smundak LastSeen time.Time 313*88d15eacSSasha Smundak } 314*88d15eacSSasha Smundak) 315*88d15eacSSasha Smundak 316*88d15eacSSasha Smundakfunc MakeGatewayInfo() (x, y Gateway) { 317*88d15eacSSasha Smundak x = Gateway{ 318*88d15eacSSasha Smundak SSID: "CoffeeShopWiFi", 319*88d15eacSSasha Smundak IPAddress: net.IPv4(192, 168, 0, 1), 320*88d15eacSSasha Smundak NetMask: net.IPv4Mask(255, 255, 0, 0), 321*88d15eacSSasha Smundak Clients: []Client{{ 322*88d15eacSSasha Smundak Hostname: "ristretto", 323*88d15eacSSasha Smundak IPAddress: net.IPv4(192, 168, 0, 116), 324*88d15eacSSasha Smundak }, { 325*88d15eacSSasha Smundak Hostname: "aribica", 326*88d15eacSSasha Smundak IPAddress: net.IPv4(192, 168, 0, 104), 327*88d15eacSSasha Smundak LastSeen: time.Date(2009, time.November, 10, 23, 6, 32, 0, time.UTC), 328*88d15eacSSasha Smundak }, { 329*88d15eacSSasha Smundak Hostname: "macchiato", 330*88d15eacSSasha Smundak IPAddress: net.IPv4(192, 168, 0, 153), 331*88d15eacSSasha Smundak LastSeen: time.Date(2009, time.November, 10, 23, 39, 43, 0, time.UTC), 332*88d15eacSSasha Smundak }, { 333*88d15eacSSasha Smundak Hostname: "espresso", 334*88d15eacSSasha Smundak IPAddress: net.IPv4(192, 168, 0, 121), 335*88d15eacSSasha Smundak }, { 336*88d15eacSSasha Smundak Hostname: "latte", 337*88d15eacSSasha Smundak IPAddress: net.IPv4(192, 168, 0, 219), 338*88d15eacSSasha Smundak LastSeen: time.Date(2009, time.November, 10, 23, 0, 23, 0, time.UTC), 339*88d15eacSSasha Smundak }, { 340*88d15eacSSasha Smundak Hostname: "americano", 341*88d15eacSSasha Smundak IPAddress: net.IPv4(192, 168, 0, 188), 342*88d15eacSSasha Smundak LastSeen: time.Date(2009, time.November, 10, 23, 3, 5, 0, time.UTC), 343*88d15eacSSasha Smundak }}, 344*88d15eacSSasha Smundak } 345*88d15eacSSasha Smundak y = Gateway{ 346*88d15eacSSasha Smundak SSID: "CoffeeShopWiFi", 347*88d15eacSSasha Smundak IPAddress: net.IPv4(192, 168, 0, 2), 348*88d15eacSSasha Smundak NetMask: net.IPv4Mask(255, 255, 0, 0), 349*88d15eacSSasha Smundak Clients: []Client{{ 350*88d15eacSSasha Smundak Hostname: "ristretto", 351*88d15eacSSasha Smundak IPAddress: net.IPv4(192, 168, 0, 116), 352*88d15eacSSasha Smundak }, { 353*88d15eacSSasha Smundak Hostname: "aribica", 354*88d15eacSSasha Smundak IPAddress: net.IPv4(192, 168, 0, 104), 355*88d15eacSSasha Smundak LastSeen: time.Date(2009, time.November, 10, 23, 6, 32, 0, time.UTC), 356*88d15eacSSasha Smundak }, { 357*88d15eacSSasha Smundak Hostname: "macchiato", 358*88d15eacSSasha Smundak IPAddress: net.IPv4(192, 168, 0, 153), 359*88d15eacSSasha Smundak LastSeen: time.Date(2009, time.November, 10, 23, 39, 43, 0, time.UTC), 360*88d15eacSSasha Smundak }, { 361*88d15eacSSasha Smundak Hostname: "espresso", 362*88d15eacSSasha Smundak IPAddress: net.IPv4(192, 168, 0, 121), 363*88d15eacSSasha Smundak }, { 364*88d15eacSSasha Smundak Hostname: "latte", 365*88d15eacSSasha Smundak IPAddress: net.IPv4(192, 168, 0, 221), 366*88d15eacSSasha Smundak LastSeen: time.Date(2009, time.November, 10, 23, 0, 23, 0, time.UTC), 367*88d15eacSSasha Smundak }}, 368*88d15eacSSasha Smundak } 369*88d15eacSSasha Smundak return x, y 370*88d15eacSSasha Smundak} 371*88d15eacSSasha Smundak 372*88d15eacSSasha Smundakvar t fakeT 373*88d15eacSSasha Smundak 374*88d15eacSSasha Smundaktype fakeT struct{} 375*88d15eacSSasha Smundak 376*88d15eacSSasha Smundakfunc (t fakeT) Errorf(format string, args ...interface{}) { fmt.Printf(format+"\n", args...) } 377