...

Source file src/k8s.io/kubectl/pkg/util/i18n/i18n_test.go

Documentation: k8s.io/kubectl/pkg/util/i18n

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package i18n
    18  
    19  import (
    20  	"os"
    21  	"sync"
    22  	"testing"
    23  
    24  	"github.com/chai2010/gettext-go"
    25  )
    26  
    27  var knownTestLocale = "en_US.UTF-8"
    28  
    29  func TestTranslation(t *testing.T) {
    30  	err := LoadTranslations("test", func() string { return "default" })
    31  	if err != nil {
    32  		t.Errorf("Unexpected error: %v", err)
    33  	}
    34  
    35  	result := T("test_string")
    36  	if result != "foo" {
    37  		t.Errorf("expected: %s, saw: %s", "foo", result)
    38  	}
    39  }
    40  
    41  func TestTranslationPlural(t *testing.T) {
    42  	err := LoadTranslations("test", func() string { return "default" })
    43  	if err != nil {
    44  		t.Errorf("Unexpected error: %v", err)
    45  	}
    46  
    47  	result := T("test_plural", 3)
    48  	if result != "there were 3 items" {
    49  		t.Errorf("expected: %s, saw: %s", "there were 3 items", result)
    50  	}
    51  
    52  	result = T("test_plural", 1)
    53  	if result != "there was 1 item" {
    54  		t.Errorf("expected: %s, saw: %s", "there was 1 item", result)
    55  	}
    56  }
    57  
    58  func TestTranslationUsingEnvVar(t *testing.T) {
    59  	// We must backup and restore env vars before setting test values in tests
    60  	// othervise we are risking to break other tests/test cases
    61  	// which rely on the same env vars
    62  	envVarsToBackup := []string{"LC_MESSAGES", "LANG", "LC_ALL"}
    63  	expectedStrEnUSLocale := "baz"
    64  	expectedStrFallback := "foo"
    65  
    66  	testCases := []struct {
    67  		name        string
    68  		setenv      map[string]string
    69  		expectedStr string
    70  	}{
    71  		{
    72  			name:        "Only LC_ALL is set",
    73  			setenv:      map[string]string{"LC_ALL": knownTestLocale},
    74  			expectedStr: expectedStrEnUSLocale,
    75  		},
    76  		{
    77  			name:        "Only LC_MESSAGES is set",
    78  			setenv:      map[string]string{"LC_MESSAGES": knownTestLocale},
    79  			expectedStr: expectedStrEnUSLocale,
    80  		},
    81  		{
    82  			name:        "Only LANG",
    83  			setenv:      map[string]string{"LANG": knownTestLocale},
    84  			expectedStr: expectedStrEnUSLocale,
    85  		},
    86  		{
    87  			name: "LC_MESSAGES overrides LANG",
    88  			setenv: map[string]string{
    89  				"LANG":        "be_BY.UTF-8", // Unknown locale
    90  				"LC_MESSAGES": knownTestLocale,
    91  			},
    92  			expectedStr: expectedStrEnUSLocale,
    93  		},
    94  		{
    95  			name: "LC_ALL overrides LANG",
    96  			setenv: map[string]string{
    97  				"LANG":   "be_BY.UTF-8", // Unknown locale
    98  				"LC_ALL": knownTestLocale,
    99  			},
   100  			expectedStr: expectedStrEnUSLocale,
   101  		},
   102  		{
   103  			name: "LC_ALL overrides LC_MESSAGES",
   104  			setenv: map[string]string{
   105  				"LC_MESSAGES": "be_BY.UTF-8", // Unknown locale
   106  				"LC_ALL":      knownTestLocale,
   107  			},
   108  			expectedStr: expectedStrEnUSLocale,
   109  		},
   110  		{
   111  			name:        "Unknown locale in LANG",
   112  			setenv:      map[string]string{"LANG": "be_BY.UTF-8"},
   113  			expectedStr: expectedStrFallback,
   114  		},
   115  		{
   116  			name:        "Unknown locale in LC_MESSAGES",
   117  			setenv:      map[string]string{"LC_MESSAGES": "be_BY.UTF-8"},
   118  			expectedStr: expectedStrFallback,
   119  		},
   120  		{
   121  			name:        "Unknown locale in LC_ALL",
   122  			setenv:      map[string]string{"LC_ALL": "be_BY.UTF-8"},
   123  			expectedStr: expectedStrFallback,
   124  		},
   125  		{
   126  			name:        "Invalid env var",
   127  			setenv:      map[string]string{"LC_MESSAGES": "fake.locale.UTF-8"},
   128  			expectedStr: expectedStrFallback,
   129  		},
   130  		{
   131  			name:        "No env vars",
   132  			expectedStr: expectedStrFallback,
   133  		},
   134  	}
   135  
   136  	for _, test := range testCases {
   137  		t.Run(test.name, func(t *testing.T) {
   138  			for _, envVar := range envVarsToBackup {
   139  				if envVarValue := os.Getenv(envVar); envVarValue != "" {
   140  					envVarValue, envVar := envVarValue, envVar
   141  					t.Cleanup(func() { os.Setenv(envVar, envVarValue) })
   142  					os.Unsetenv(envVar)
   143  				}
   144  			}
   145  
   146  			for envVar, envVarValue := range test.setenv {
   147  				t.Setenv(envVar, envVarValue)
   148  			}
   149  
   150  			err := LoadTranslations("test", nil)
   151  			if err != nil {
   152  				t.Errorf("Unexpected error: %v", err)
   153  			}
   154  
   155  			result := T("test_string")
   156  			if result != test.expectedStr {
   157  				t.Errorf("expected: %s, saw: %s", test.expectedStr, result)
   158  			}
   159  		})
   160  	}
   161  }
   162  
   163  // resetLazyLoading allows multiple tests to test translation lazy loading by resetting the state
   164  func resetLazyLoading() {
   165  	translationsLoaded = false
   166  	lazyLoadTranslationsOnce = sync.Once{}
   167  }
   168  
   169  func TestLazyLoadTranslationFuncIsCalled(t *testing.T) {
   170  	resetLazyLoading()
   171  
   172  	timesCalled := 0
   173  	err := SetLoadTranslationsFunc(func() error {
   174  		timesCalled++
   175  		return LoadTranslations("test", func() string { return "en_US" })
   176  	})
   177  	if err != nil {
   178  		t.Errorf("unexpected error: %v", err)
   179  	}
   180  	if translationsLoaded {
   181  		t.Errorf("expected translationsLoaded to be false, but it was true")
   182  	}
   183  
   184  	// Translation should succeed and use the lazy loaded translations
   185  	result := T("test_string")
   186  	if result != "baz" {
   187  		t.Errorf("expected: %s, saw: %s", "baz", result)
   188  	}
   189  	if timesCalled != 1 {
   190  		t.Errorf("expected LoadTranslationsFunc to have been called 1 time, but it was called %d times", timesCalled)
   191  	}
   192  	if !translationsLoaded {
   193  		t.Errorf("expected translationsLoaded to be true, but it was false")
   194  	}
   195  
   196  	// Call T() again, and timesCalled should remain 1
   197  	T("test_string")
   198  	if timesCalled != 1 {
   199  		t.Errorf("expected LoadTranslationsFunc to have been called 1 time, but it was called %d times", timesCalled)
   200  	}
   201  }
   202  
   203  func TestLazyLoadTranslationFuncOnlyCalledIfTranslationsNotLoaded(t *testing.T) {
   204  	resetLazyLoading()
   205  
   206  	// Set a custom translations func
   207  	timesCalled := 0
   208  	err := SetLoadTranslationsFunc(func() error {
   209  		timesCalled++
   210  		return LoadTranslations("test", func() string { return "en_US" })
   211  	})
   212  	if err != nil {
   213  		t.Errorf("unexpected error: %v", err)
   214  	}
   215  	if translationsLoaded {
   216  		t.Errorf("expected translationsLoaded to be false, but it was true")
   217  	}
   218  
   219  	// Explicitly load translations before lazy loading can occur
   220  	err = LoadTranslations("test", func() string { return "default" })
   221  	if err != nil {
   222  		t.Errorf("Unexpected error: %v", err)
   223  	}
   224  	if !translationsLoaded {
   225  		t.Errorf("expected translationsLoaded to be true, but it was false")
   226  	}
   227  
   228  	// Translation should succeed, and use the explicitly loaded translations, not the lazy loaded ones
   229  	result := T("test_string")
   230  	if result != "foo" {
   231  		t.Errorf("expected: %s, saw: %s", "foo", result)
   232  	}
   233  	if timesCalled != 0 {
   234  		t.Errorf("expected LoadTranslationsFunc to have not been called, but it was called %d times", timesCalled)
   235  	}
   236  }
   237  
   238  func TestSetCustomLoadTranslationsFunc(t *testing.T) {
   239  	resetLazyLoading()
   240  
   241  	// Set a custom translations func that loads translations from a directory
   242  	err := SetLoadTranslationsFunc(func() error {
   243  		gettext.BindLocale(gettext.New("k8s", "./translations/test"))
   244  		gettext.SetDomain("k8s")
   245  		gettext.SetLanguage("en_US")
   246  		return nil
   247  	})
   248  	if err != nil {
   249  		t.Errorf("unexpected error: %v", err)
   250  	}
   251  	if translationsLoaded {
   252  		t.Errorf("expected translationsLoaded to be false, but it was true")
   253  	}
   254  
   255  	// Translation should succeed
   256  	result := T("test_string")
   257  	if result != "baz" {
   258  		t.Errorf("expected: %s, saw: %s", "baz", result)
   259  	}
   260  	if !translationsLoaded {
   261  		t.Errorf("expected translationsLoaded to be true, but it was false")
   262  	}
   263  }
   264  
   265  func TestSetCustomLoadTranslationsFuncAfterTranslationsLoadedShouldFail(t *testing.T) {
   266  	resetLazyLoading()
   267  
   268  	// Explicitly load translations
   269  	err := LoadTranslations("test", func() string { return "en_US" })
   270  	if err != nil {
   271  		t.Errorf("Unexpected error: %v", err)
   272  	}
   273  	if !translationsLoaded {
   274  		t.Errorf("expected translationsLoaded to be true, but it was false")
   275  	}
   276  
   277  	// This should fail because translations have already been loaded, and the custom function should not be called.
   278  	timesCalled := 0
   279  	err = SetLoadTranslationsFunc(func() error {
   280  		timesCalled++
   281  		return nil
   282  	})
   283  	if err == nil {
   284  		t.Errorf("expected error, but it did not occur")
   285  	}
   286  	if timesCalled != 0 {
   287  		t.Errorf("expected LoadTranslationsFunc to have not been called, but it was called %d times", timesCalled)
   288  	}
   289  }
   290  

View as plain text