github.com/CharukaK/i18n4go@v0.6.0/integration/fixup/fixup_test.go (about) 1 // Copyright © 2015-2023 The Knative Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package fixup_test 16 17 import ( 18 "bufio" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "os" 23 "os/exec" 24 "path/filepath" 25 "strings" 26 27 "github.com/CharukaK/i18n4go/i18n4go/common" 28 29 . "github.com/CharukaK/i18n4go/integration/test_helpers" 30 . "github.com/onsi/ginkgo" 31 . "github.com/onsi/gomega" 32 ) 33 34 var _ = Describe("fixup", func() { 35 var ( 36 fixturesPath string 37 cmd *exec.Cmd 38 stdinPipe io.WriteCloser 39 stdoutPipe io.ReadCloser 40 stdoutReader *bufio.Reader 41 curDir string 42 jsonFiles map[string][]byte 43 err error 44 ) 45 46 BeforeEach(func() { 47 curDir, err = os.Getwd() 48 if err != nil { 49 fmt.Println("Could not get working directory") 50 panic(err.Error()) 51 } 52 }) 53 54 AfterEach(func() { 55 // restore json files 56 for path, bytes := range jsonFiles { 57 err = ioutil.WriteFile(path, bytes, 0666) 58 if err != nil { 59 fmt.Println("Could not rewrite backup JSON files") 60 panic(err.Error()) 61 } 62 } 63 64 err = os.Chdir(curDir) 65 if err != nil { 66 fmt.Println("Could not change back to working directory") 67 panic(err.Error()) 68 } 69 }) 70 71 JustBeforeEach(func() { 72 err = os.Chdir(fixturesPath) 73 if err != nil { 74 fmt.Println("Could not change to fixtures directory") 75 panic(err.Error()) 76 } 77 78 // backup json files 79 jsonFiles, err = storeTranslationFiles(".") 80 if err != nil { 81 fmt.Println("Could not back up the JSON files.") 82 panic(err.Error()) 83 } 84 85 //session = Runi18n("-c", "fixup") 86 cmd = exec.Command(I18n4goExec, "-c", "fixup") 87 88 stdinPipe, err = cmd.StdinPipe() 89 if err != nil { 90 fmt.Println("Could not get the stdin pipe.") 91 panic(err.Error()) 92 } 93 94 stdoutPipe, err = cmd.StdoutPipe() 95 if err != nil { 96 fmt.Println("Could not get the stdout pipe.") 97 panic(err.Error()) 98 } 99 stdoutReader = bufio.NewReader(stdoutPipe) 100 101 _, err = cmd.StderrPipe() 102 if err != nil { 103 fmt.Println("Could not get the stderr pipe.") 104 panic(err.Error()) 105 } 106 107 err = cmd.Start() 108 if err != nil { 109 fmt.Println("Could not run fixup") 110 panic(err.Error()) 111 } 112 }) 113 114 Context("When there are no problems", func() { 115 BeforeEach(func() { 116 fixturesPath = filepath.Join("..", "..", "test_fixtures", "fixup", "allgood") 117 }) 118 119 It("returns 0 and prints a reassuring message", func() { 120 Ω(getNextOutputLine(stdoutReader)).Should(Equal("OK")) 121 122 exitCode := cmd.Wait() 123 Ω(exitCode).Should(BeNil()) 124 }) 125 126 Context("for adding", func() { 127 It("does not print empty add messages", func() { 128 Ω(getNextOutputLine(stdoutReader)).ShouldNot(ContainSubstring("Adding these strings")) 129 130 exitCode := cmd.Wait() 131 Ω(exitCode).Should(BeNil()) 132 }) 133 }) 134 135 Context("for deleting", func() { 136 It("does not print empty delete messages", func() { 137 Ω(getNextOutputLine(stdoutReader)).ShouldNot(ContainSubstring("Removing these strings")) 138 139 exitCode := cmd.Wait() 140 Ω(exitCode).Should(BeNil()) 141 }) 142 }) 143 144 Context("For updating", func() { 145 It("does not print empty new or update check message", func() { 146 Ω(getNextOutputLine(stdoutReader)).ShouldNot(ContainSubstring("new or updated string")) 147 148 exitCode := cmd.Wait() 149 Ω(exitCode).Should(BeNil()) 150 }) 151 }) 152 }) 153 154 Context("When there are brand new strings in the code that don't exist in en_US", func() { 155 BeforeEach(func() { 156 fixturesPath = filepath.Join("..", "..", "test_fixtures", "fixup", "notsogood", "add") 157 }) 158 159 It("adds strings to all the locales", func() { 160 Ω(getNextOutputLine(stdoutReader)).Should(ContainSubstring("Adding these strings")) 161 Ω(getNextOutputLine(stdoutReader)).Should(ContainSubstring("Heal the world")) 162 163 exitCode := cmd.Wait() 164 Ω(exitCode).Should(BeNil()) 165 166 file, err := ioutil.ReadFile(filepath.Join(".", "translations", "en_US.all.json")) 167 Ω(err).ShouldNot(HaveOccurred()) 168 Ω(file).Should(ContainSubstring("\"Heal the world\"")) 169 170 chineseFile, err := ioutil.ReadFile(filepath.Join(".", "translations", "zh_CN.all.json")) 171 Ω(err).ShouldNot(HaveOccurred()) 172 Ω(chineseFile).Should(ContainSubstring("\"Heal the world\"")) 173 }) 174 }) 175 176 Context("When there are old strings in the translations that don't exist in the code", func() { 177 BeforeEach(func() { 178 fixturesPath = filepath.Join("..", "..", "test_fixtures", "fixup", "notsogood", "delete") 179 }) 180 181 It("removes the strings from all the locales", func() { 182 Ω(getNextOutputLine(stdoutReader)).Should(ContainSubstring("Removing these strings")) 183 Ω(getNextOutputLine(stdoutReader)).Should(ContainSubstring("Heal the world")) 184 185 exitCode := cmd.Wait() 186 Ω(exitCode).Should(BeNil()) 187 188 file, err := ioutil.ReadFile(filepath.Join(".", "translations", "en_US.all.json")) 189 Ω(err).ShouldNot(HaveOccurred()) 190 Ω(file).ShouldNot(ContainSubstring("\"Heal the world\"")) 191 192 chineseFile, err := ioutil.ReadFile(filepath.Join(".", "translations", "zh_CN.all.json")) 193 Ω(err).ShouldNot(HaveOccurred()) 194 Ω(chineseFile).ShouldNot(ContainSubstring("\"Heal the world\"")) 195 }) 196 }) 197 198 Context("When a string has been updated or added in the code", func() { 199 BeforeEach(func() { 200 fixturesPath = filepath.Join("..", "..", "test_fixtures", "fixup", "notsogood", "update") 201 }) 202 203 It("cancels the interactive update when a user types exit", func() { 204 Ω(getNextOutputLine(stdoutReader)).Should(ContainSubstring("Is the string \"I like apples.\" a new or updated string? [new/upd]")) 205 206 stdinPipe.Write([]byte("exit\n")) 207 Ω(getNextOutputLine(stdoutReader)).Should(ContainSubstring("Canceling fixup")) 208 209 exitCode := cmd.Wait() 210 Ω(exitCode).Should(BeNil()) 211 }) 212 213 It("prompts the user again if they do not input a correct response", func() { 214 Ω(getNextOutputLine(stdoutReader)).Should(ContainSubstring("Is the string \"I like apples.\" a new or updated string? [new/upd]")) 215 216 stdinPipe.Write([]byte("nope\n")) 217 218 Ω(getNextOutputLine(stdoutReader)).Should(ContainSubstring("Invalid response")) 219 Ω(getNextOutputLine(stdoutReader)).Should(ContainSubstring("Is the string \"I like apples.\" a new or updated string? [new/upd]")) 220 221 stdinPipe.Write([]byte("exit\n")) 222 223 exitCode := cmd.Wait() 224 Ω(exitCode).Should(BeNil()) 225 }) 226 227 Context("When the user says the translation was updated", func() { 228 JustBeforeEach(func() { 229 Ω(getNextOutputLine(stdoutReader)).Should(ContainSubstring("Is the string \"I like apples.\" a new or updated string? [new/upd]")) 230 stdinPipe.Write([]byte("upd\n")) 231 stdinPipe.Write([]byte("1\n")) 232 }) 233 234 It("Updates the keys for all translation files", func() { 235 cmd.Wait() 236 237 translations, err := common.LoadI18nStringInfos(filepath.Join(".", "translations", "en_US.all.json")) 238 Ω(err).ShouldNot(HaveOccurred()) 239 mappedTranslations, err := common.CreateI18nStringInfoMap(translations) 240 Ω(err).ShouldNot(HaveOccurred()) 241 Ω(mappedTranslations["I like bananas."]).Should(Equal(common.I18nStringInfo{})) 242 Ω(mappedTranslations["I like apples."]).ShouldNot(Equal(common.I18nStringInfo{})) 243 244 translations, err = common.LoadI18nStringInfos(filepath.Join(".", "translations", "zh_CN.all.json")) 245 Ω(err).ShouldNot(HaveOccurred()) 246 mappedTranslations, err = common.CreateI18nStringInfoMap(translations) 247 Ω(err).ShouldNot(HaveOccurred()) 248 Ω(mappedTranslations["I like bananas."]).Should(Equal(common.I18nStringInfo{})) 249 Ω(mappedTranslations["I like apples."]).ShouldNot(Equal(common.I18nStringInfo{})) 250 }) 251 252 It("Updates all the translation", func() { 253 cmd.Wait() 254 255 translations, err := common.LoadI18nStringInfos(filepath.Join(".", "translations", "en_US.all.json")) 256 Ω(err).ShouldNot(HaveOccurred()) 257 mappedTranslations, err := common.CreateI18nStringInfoMap(translations) 258 Ω(err).ShouldNot(HaveOccurred()) 259 Ω(mappedTranslations["I like apples."].Translation).Should(Equal("I like apples.")) 260 }) 261 262 It("marks the foreign language translations as updated", func() { 263 cmd.Wait() 264 265 translations, err := common.LoadI18nStringInfos(filepath.Join(".", "translations", "zh_CN.all.json")) 266 Ω(err).ShouldNot(HaveOccurred()) 267 mappedTranslations, err := common.CreateI18nStringInfoMap(translations) 268 Ω(err).ShouldNot(HaveOccurred()) 269 270 Ω(mappedTranslations["I like apples."].Translation).ShouldNot(Equal("I like apples.")) 271 }) 272 }) 273 274 Context("When the user says the translation is new", func() { 275 var ( 276 apple = common.I18nStringInfo{ID: "I like apples.", Translation: "I like apples."} 277 ) 278 279 JustBeforeEach(func() { 280 Ω(getNextOutputLine(stdoutReader)).Should(ContainSubstring("Is the string \"I like apples.\" a new or updated string? [new/upd]")) 281 stdinPipe.Write([]byte("new\n")) 282 }) 283 284 It("adds the new translation and deletes the old translation from all translation files", func() { 285 cmd.Wait() 286 287 translations, err := common.LoadI18nStringInfos(filepath.Join(".", "translations", "en_US.all.json")) 288 Ω(err).ShouldNot(HaveOccurred()) 289 mappedTranslations, err := common.CreateI18nStringInfoMap(translations) 290 Ω(err).ShouldNot(HaveOccurred()) 291 Ω(mappedTranslations["I like bananas."]).Should(Equal(common.I18nStringInfo{})) 292 Ω(mappedTranslations["I like apples."]).Should(Equal(apple)) 293 294 translations, err = common.LoadI18nStringInfos(filepath.Join(".", "translations", "zh_CN.all.json")) 295 Ω(err).ShouldNot(HaveOccurred()) 296 mappedTranslations, err = common.CreateI18nStringInfoMap(translations) 297 Ω(err).ShouldNot(HaveOccurred()) 298 Ω(mappedTranslations["I like bananas."]).Should(Equal(common.I18nStringInfo{})) 299 Ω(mappedTranslations["I like apples."]).Should(Equal(apple)) 300 }) 301 }) 302 }) 303 304 Context("When a foreign language is missing an english translation", func() { 305 BeforeEach(func() { 306 fixturesPath = filepath.Join("..", "..", "test_fixtures", "fixup", "notsogood", "missing_foreign_key") 307 }) 308 309 It("adds the extra translation", func() { 310 cmd.Wait() 311 312 translations, err := common.LoadI18nStringInfos(filepath.Join(".", "translations", "zh_CN.all.json")) 313 Ω(err).ShouldNot(HaveOccurred()) 314 mappedTranslations, err := common.CreateI18nStringInfoMap(translations) 315 Ω(err).ShouldNot(HaveOccurred()) 316 Ω(mappedTranslations["I'm the extra key"]).Should(Equal( 317 common.I18nStringInfo{ID: "I'm the extra key", Translation: "I'm the extra key"}, 318 )) 319 }) 320 }) 321 322 Context("When a foreign language has an extra key", func() { 323 BeforeEach(func() { 324 fixturesPath = filepath.Join("..", "..", "test_fixtures", "fixup", "notsogood", "extra_foreign_key") 325 }) 326 327 It("removes the extra translation", func() { 328 cmd.Wait() 329 330 translations, err := common.LoadI18nStringInfos(filepath.Join(".", "translations", "zh_CN.all.json")) 331 Ω(err).ShouldNot(HaveOccurred()) 332 mappedTranslations, err := common.CreateI18nStringInfoMap(translations) 333 Ω(err).ShouldNot(HaveOccurred()) 334 Ω(mappedTranslations["I'm the extra key"]).Should(Equal(common.I18nStringInfo{})) 335 }) 336 }) 337 }) 338 339 func storeTranslationFiles(dir string) (files map[string][]byte, err error) { 340 files = make(map[string][]byte) 341 contents, _ := ioutil.ReadDir(dir) 342 343 for _, fileInfo := range contents { 344 if !fileInfo.IsDir() { 345 name := fileInfo.Name() 346 347 if strings.HasSuffix(name, ".all.json") { 348 path := filepath.Join(dir, fileInfo.Name()) 349 files[path], err = ioutil.ReadFile(path) 350 351 if err != nil { 352 return nil, err 353 } 354 } 355 } else { 356 newFiles, err := storeTranslationFiles(filepath.Join(dir, fileInfo.Name())) 357 if err != nil { 358 return nil, err 359 } 360 361 for path, bytes := range newFiles { 362 files[path] = bytes 363 } 364 } 365 } 366 367 return 368 } 369 370 func getNextOutputLine(reader *bufio.Reader) string { 371 line, _, err := reader.ReadLine() 372 if err != nil { 373 panic(err) 374 } 375 376 return string(line) 377 }