github.com/Aoi-hosizora/ahlib@v1.5.1-0.20230404072829-241b93cf91c7/xconstant/zones/generate_test.go (about) 1 package zones 2 3 import ( 4 "archive/zip" 5 "bytes" 6 "fmt" 7 "github.com/Aoi-hosizora/ahlib/xstring" 8 "github.com/Aoi-hosizora/ahlib/xtime" 9 "go/format" 10 "io" 11 "io/ioutil" 12 "math" 13 "os" 14 "path/filepath" 15 "runtime" 16 "strings" 17 "testing" 18 "time" 19 ) 20 21 func TestGenerate(t *testing.T) { 22 _ = generate 23 // err := generate() 24 // if err != nil { 25 // log.Fatalln(err) 26 // } 27 } 28 29 func generate() error { 30 nameList, setList, err := getList() 31 if err != nil { 32 return fmt.Errorf("getList: %w", err) 33 } 34 35 // 1. code 36 sb := bytes.Buffer{} 37 sb.WriteString(`// Code generated by generate_test. DO NOT EDIT. 38 39 package zones 40 41 // Time zones are referred from "${runtime.GOROOT()}/lib/time/zoneinfo.zip". 42 43 const ( 44 ` + strings.Join(setList, "\n") + ` 45 )`) 46 err = formatAndWrite(sb.Bytes(), "_generate/zones.go") 47 if err != nil { 48 return fmt.Errorf("code formatAndWrite: %w", err) 49 } 50 51 // 2. test code 52 sb.Reset() 53 sb.WriteString(`// Code generated by generate_test. DO NOT EDIT. 54 55 package zones 56 57 import ( 58 "github.com/Aoi-hosizora/ahlib/xtesting" 59 "testing" 60 "time" 61 ) 62 63 func TestZones(t *testing.T) { 64 for _, zone := range []string{ 65 ` + strings.Join(nameList, ",\n") + `, 66 } { 67 _, err := time.LoadLocation(zone) 68 xtesting.Nil(t, err) 69 } 70 }`) 71 err = formatAndWrite(sb.Bytes(), "_generate/zones_test.go") 72 if err != nil { 73 return fmt.Errorf("test code formatAndWrite: %w", err) 74 } 75 76 return nil 77 } 78 79 func formatAndWrite(bs []byte, filename string) error { 80 bs, err := format.Source(bs) 81 if err != nil { 82 return err 83 } 84 err = os.MkdirAll(filepath.Dir(filename), 0644) 85 if err != nil { 86 return err 87 } 88 f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) 89 if err != nil { 90 return err 91 } 92 defer f.Close() 93 _, err = f.Write(bs) 94 if err != nil { 95 return err 96 } 97 return nil 98 } 99 100 func unzip(srcFile string, dstDir string) error { 101 archive, err := zip.OpenReader(srcFile) 102 if err != nil { 103 return err 104 } 105 defer archive.Close() 106 107 for _, f := range archive.File { 108 path := filepath.Join(dstDir, f.Name) 109 if f.FileInfo().IsDir() { 110 if err := os.MkdirAll(path, 0644); err != nil { 111 return err 112 } 113 continue 114 } 115 if err := os.MkdirAll(filepath.Dir(path), 0644); err != nil { 116 return err 117 } 118 fileInArchive, err := f.Open() 119 if err != nil { 120 return err 121 } 122 dstFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) 123 if err != nil { 124 return err 125 } 126 127 if _, err := io.Copy(dstFile, fileInArchive); err != nil { 128 return err 129 } 130 _ = dstFile.Close() 131 _ = fileInArchive.Close() 132 } 133 134 return nil 135 } 136 137 func getList() (varNameList []string, varSetList []string, err error) { 138 zoneSource := filepath.Join(runtime.GOROOT(), "lib/time/zoneinfo.zip") 139 tempDir := "./temp" 140 err = unzip(zoneSource, tempDir) 141 if err != nil { 142 return nil, nil, fmt.Errorf("unzip: %w", err) 143 } 144 defer os.RemoveAll(tempDir) 145 146 // read zoneinfo folder 147 result := make([]string, 0) 148 var readDir func(path string) error 149 readDir = func(path string) error { 150 files, err := ioutil.ReadDir(filepath.Join(tempDir, path)) 151 if err != nil { 152 return err 153 } 154 for _, entry := range files { 155 name := entry.Name() 156 if name != strings.ToUpper(name[:1])+name[1:] { 157 continue 158 } 159 if entry.IsDir() { 160 err = readDir(path + "/" + name) 161 if err != nil { 162 return err 163 } 164 } else { 165 result = append(result, (path + "/" + name)[1:]) 166 } 167 } 168 return nil 169 } 170 err = readDir("") 171 if err != nil { 172 return nil, nil, fmt.Errorf("readDir: %w", err) 173 } 174 175 // generate final list 176 varNameList = make([]string, 0, len(result)+2) 177 varSetList = make([]string, 0, len(result)+2) 178 varNameList = append(varNameList, "UTC", "Local") 179 varSetList = append(varSetList, `UTC = "UTC" // time.UTC`, `Local = "Local" // time.Local`) 180 for _, r := range result { 181 loc, err := time.LoadLocation(r) 182 if err != nil { 183 return nil, nil, fmt.Errorf("LoadLocation: %w", err) 184 } 185 words := xstring.SplitToWords(loc.String(), "/") 186 for i, w := range words { 187 if strings.HasPrefix(w, "Etc") || strings.HasPrefix(w, "GMT") { 188 // skip 189 } else { 190 w = xstring.PascalCase(w) 191 } 192 words[i] = w 193 } 194 varName := strings.Join(words, "_") 195 196 du := xtime.LocationDuration(loc) 197 flag := "+" 198 if du < 0 { 199 flag = "-" 200 } 201 comment := fmt.Sprintf("%s%02d:%02d", flag, int(math.Abs(du.Hours())), xtime.DurationMinuteComponent(du)) 202 203 if varName == "UTC" { 204 continue 205 } else if strings.HasPrefix(varName, "Etc") || strings.HasPrefix(varName, "GMT") { 206 varName = strings.Replace(varName, "+", "_P", 1) 207 varName = strings.Replace(varName, "-", "_M", 1) 208 } 209 varNameList = append(varNameList, varName) 210 varSetList = append(varSetList, fmt.Sprintf("%s = \"%s\" // %s", varName, loc.String(), comment)) 211 } 212 return varNameList, varSetList, nil 213 }