1// Copyright 2020 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package time_test 6 7import ( 8 "reflect" 9 "testing" 10 "time" 11 _ "time/tzdata" 12) 13 14var zones = []string{ 15 "Asia/Jerusalem", 16 "America/Los_Angeles", 17} 18 19func TestEmbeddedTZData(t *testing.T) { 20 undo := time.DisablePlatformSources() 21 defer undo() 22 23 for _, zone := range zones { 24 ref, err := time.LoadLocation(zone) 25 if err != nil { 26 t.Errorf("LoadLocation(%q): %v", zone, err) 27 continue 28 } 29 30 embedded, err := time.LoadFromEmbeddedTZData(zone) 31 if err != nil { 32 t.Errorf("LoadFromEmbeddedTZData(%q): %v", zone, err) 33 continue 34 } 35 sample, err := time.LoadLocationFromTZData(zone, []byte(embedded)) 36 if err != nil { 37 t.Errorf("LoadLocationFromTZData failed for %q: %v", zone, err) 38 continue 39 } 40 41 // Compare the name and zone fields of ref and sample. 42 // The tx field changes faster as tzdata is updated. 43 // The cache fields are expected to differ. 44 v1 := reflect.ValueOf(ref).Elem() 45 v2 := reflect.ValueOf(sample).Elem() 46 typ := v1.Type() 47 nf := typ.NumField() 48 found := 0 49 for i := 0; i < nf; i++ { 50 ft := typ.Field(i) 51 if ft.Name != "name" && ft.Name != "zone" { 52 continue 53 } 54 found++ 55 if !equal(t, v1.Field(i), v2.Field(i)) { 56 t.Errorf("zone %s: system and embedded tzdata field %s differs", zone, ft.Name) 57 } 58 } 59 if found != 2 { 60 t.Errorf("test must be updated for change to time.Location struct") 61 } 62 } 63} 64 65// equal is a small version of reflect.DeepEqual that we use to 66// compare the values of zoneinfo unexported fields. 67func equal(t *testing.T, f1, f2 reflect.Value) bool { 68 switch f1.Type().Kind() { 69 case reflect.Slice: 70 if f1.Len() != f2.Len() { 71 return false 72 } 73 for i := 0; i < f1.Len(); i++ { 74 if !equal(t, f1.Index(i), f2.Index(i)) { 75 return false 76 } 77 } 78 return true 79 case reflect.Struct: 80 nf := f1.Type().NumField() 81 for i := 0; i < nf; i++ { 82 if !equal(t, f1.Field(i), f2.Field(i)) { 83 return false 84 } 85 } 86 return true 87 case reflect.String: 88 return f1.String() == f2.String() 89 case reflect.Bool: 90 return f1.Bool() == f2.Bool() 91 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 92 return f1.Int() == f2.Int() 93 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 94 return f1.Uint() == f2.Uint() 95 default: 96 t.Errorf("test internal error: unsupported kind %v", f1.Type().Kind()) 97 return true 98 } 99} 100