package localizer import ( "testing" "git.perx.ru/perxis/perxis-go/pkg/locales" "git.perx.ru/perxis/perxis-go/pkg/schema" "git.perx.ru/perxis/perxis-go/pkg/schema/field" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestLocalizer_localize(t *testing.T) { s := schema.New( "a", field.String(), "b", field.Number(field.NumberFormatInt), "c", field.String().SetSingleLocale(true), "obj1", field.Object( "a", field.String(), "b", field.Number(field.NumberFormatInt), "c", field.Number(field.NumberFormatInt).SetSingleLocale(true), "obj2", field.Object( "a", field.Number(field.NumberFormatInt), "b", field.String(), "c", field.String().SetSingleLocale(true), ), ), "obj3", field.Object( "a", field.String(), ).SetSingleLocale(true), "slice", field.Array(field.String()), "arr", field.Array(field.Object( "num", field.Number(field.NumberFormatInt), )), ) tests := []struct { fallback map[string]interface{} target map[string]interface{} want map[string]interface{} name string wantErr bool }{ { name: "Nil", fallback: nil, target: nil, want: nil, }, { name: "Empty", fallback: map[string]interface{}{}, target: map[string]interface{}{}, want: map[string]interface{}{}, }, { name: "Target Empty", fallback: map[string]interface{}{ "a": "en", "b": 1, "c": "single", "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "c": 20, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", "c": "obj1_obj2_single", }, }, "obj3": map[string]interface{}{ "a": "obj3_en", }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, target: map[string]interface{}{}, want: map[string]interface{}{ "a": "en", "b": 1, "c": "single", "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "c": 20, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", "c": "obj1_obj2_single", }, }, "obj3": map[string]interface{}{ "a": "obj3_en", }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, }, { name: "Fallback Empty", fallback: map[string]interface{}{}, target: map[string]interface{}{ "a": "en", "b": 1, "c": "single", "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "c": 20, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", "c": "obj1_obj2_single", }, }, "obj3": map[string]interface{}{ "a": "obj3_en", }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, want: map[string]interface{}{ "a": "en", "b": 1, "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", }, }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, }, { name: "Equal", fallback: map[string]interface{}{ "a": "en", "b": 1, "c": "single", "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "c": 20, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", "c": "obj1_obj2_single", }, }, "obj3": map[string]interface{}{ "a": "obj3_en", }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, target: map[string]interface{}{ "a": "en", "b": 1, "c": "single", "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "c": 20, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", "c": "obj1_obj2_single", }, }, "obj3": map[string]interface{}{ "a": "obj3_en", }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, want: map[string]interface{}{ "a": "en", "b": 1, "c": "single", "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "c": 20, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", "c": "obj1_obj2_single", }, }, "obj3": map[string]interface{}{ "a": "obj3_en", }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, }, { name: "Target no single", fallback: map[string]interface{}{ "a": "en", "b": 1, "c": "single", "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "c": 20, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", "c": "obj1_obj2_single", }, }, "obj3": map[string]interface{}{ "a": "obj3_en", }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, target: map[string]interface{}{ "a": "en", "b": 1, "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", }, }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, want: map[string]interface{}{ "a": "en", "b": 1, "c": "single", "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "c": 20, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", "c": "obj1_obj2_single", }, }, "obj3": map[string]interface{}{ "a": "obj3_en", }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, }, { name: "Success", fallback: map[string]interface{}{ "a": "en", "b": 1, "c": "single", "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "c": 20, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", "c": "obj1_obj2_single", }, }, "obj3": map[string]interface{}{ "a": "obj3_en", }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, target: map[string]interface{}{ "a": "ru", "b": 11, "obj1": map[string]interface{}{ "a": "obj1_ru", "b": 22, "obj2": map[string]interface{}{ "a": 33, "b": "obj1_obj2_ru", }, }, "slice": []interface{}{"ru_s3"}, "arr": []interface{}{ map[string]interface{}{"num": 1}, map[string]interface{}{"num": 2}, }, }, want: map[string]interface{}{ "a": "ru", "b": 11, "c": "single", "obj1": map[string]interface{}{ "a": "obj1_ru", "b": 22, "c": 20, "obj2": map[string]interface{}{ "a": 33, "b": "obj1_obj2_ru", "c": "obj1_obj2_single", }, }, "obj3": map[string]interface{}{ "a": "obj3_en", }, "slice": []interface{}{"ru_s3"}, "arr": []interface{}{ map[string]interface{}{"num": 1}, map[string]interface{}{"num": 2}, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { l := &Localizer{ schema: s, } got, err := l.localize(tt.target, tt.fallback) if !tt.wantErr { require.NoError(t, err) assert.Equal(t, tt.want, got) return } require.Error(t, err) }) } } func TestLocalizer_deLocalize(t *testing.T) { s := schema.New( "a", field.String(), "b", field.Number(field.NumberFormatInt), "c", field.String().SetSingleLocale(true), "obj1", field.Object( "a", field.String(), "b", field.Number(field.NumberFormatInt), "c", field.Number(field.NumberFormatInt).SetSingleLocale(true), "obj2", field.Object( "a", field.Number(field.NumberFormatInt), "b", field.String(), "c", field.String().SetSingleLocale(true), ), ), "obj3", field.Object( "a", field.String(), ).SetSingleLocale(true), "slice", field.Array(field.String()), "arr", field.Array(field.Object( "num", field.Number(field.NumberFormatInt), )), ) tests := []struct { fallback map[string]interface{} target map[string]interface{} want map[string]interface{} name string wantErr bool }{ { name: "Nil", fallback: nil, target: nil, want: nil, }, { name: "Empty", fallback: map[string]interface{}{}, target: map[string]interface{}{}, want: map[string]interface{}{}, }, { name: "Target Empty", fallback: map[string]interface{}{ "a": "en", "b": 1, "c": "single", "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "c": 20, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", "c": "obj1_obj2_single", }, }, "obj3": map[string]interface{}{ "a": "obj3_en", }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, target: map[string]interface{}{}, want: map[string]interface{}{}, }, { name: "Fallback Empty", fallback: map[string]interface{}{}, target: map[string]interface{}{ "a": "en", "b": 1, "c": "single", "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "c": 20, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", "c": "obj1_obj2_single", }, }, "obj3": map[string]interface{}{ "a": "obj3_en", }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, want: map[string]interface{}{ "a": "en", "b": 1, "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", }, }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, }, { name: "Equal", fallback: map[string]interface{}{ "a": "en", "b": 1, "c": "single", "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "c": 20, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", "c": "obj1_obj2_single", }, }, "obj3": map[string]interface{}{ "a": "obj3_en", }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, target: map[string]interface{}{ "a": "en", "b": 1, "c": "single", "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "c": 20, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", "c": "obj1_obj2_single", }, }, "obj3": map[string]interface{}{ "a": "obj3_en", }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, want: map[string]interface{}{}, }, { name: "Success", fallback: map[string]interface{}{ "a": "en", "b": 1, "c": "single", "obj1": map[string]interface{}{ "a": "obj1_en", "b": 2, "c": 20, "obj2": map[string]interface{}{ "a": 3, "b": "obj1_obj2_en", "c": "obj1_obj2_single", }, }, "obj3": map[string]interface{}{ "a": "obj3_en", }, "slice": []interface{}{"en_s1", "en_s2"}, "arr": []interface{}{ map[string]interface{}{"num": 11}, map[string]interface{}{"num": 22}, }, }, target: map[string]interface{}{ "a": "ru", "b": 11, "obj1": map[string]interface{}{ "a": "obj1_ru", "b": 22, "obj2": map[string]interface{}{ "a": 33, "b": "obj1_obj2_ru", }, }, "slice": []interface{}{"ru_s3"}, "arr": []interface{}{ map[string]interface{}{"num": 1}, map[string]interface{}{"num": 2}, }, }, want: map[string]interface{}{ "a": "ru", "b": 11, "obj1": map[string]interface{}{ "a": "obj1_ru", "b": 22, "obj2": map[string]interface{}{ "a": 33, "b": "obj1_obj2_ru", }, }, "slice": []interface{}{"ru_s3"}, "arr": []interface{}{ map[string]interface{}{"num": 1}, map[string]interface{}{"num": 2}, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { l := &Localizer{ schema: s, } got, err := l.extractTranslation(tt.target, tt.fallback) if !tt.wantErr { require.NoError(t, err) assert.Equal(t, tt.want, got) return } require.Error(t, err) }) } } func TestLocalizer_getTargetAndFallBackLocales(t *testing.T) { tests := []struct { localizer *Localizer wantTarget *locales.Locale wantFallback *locales.Locale name string wantErr bool }{ { name: "Empty", localizer: &Localizer{}, wantErr: true, }, { name: "Success", localizer: &Localizer{ localeID: "en", localesKV: map[string]*locales.Locale{ "en": {ID: "en"}, "default": {ID: "default"}, }, }, wantTarget: &locales.Locale{ID: "en"}, wantFallback: &locales.Locale{ID: "default"}, }, { name: "Success fallback", localizer: &Localizer{ localeID: "ru", localesKV: map[string]*locales.Locale{ "en": {ID: "en"}, "ru": {ID: "ru", Fallback: "en"}, "default": {ID: "default"}, }, }, wantTarget: &locales.Locale{ID: "ru", Fallback: "en"}, wantFallback: &locales.Locale{ID: "en"}, }, { name: "Success fallback no default", localizer: &Localizer{ localeID: "ru", localesKV: map[string]*locales.Locale{ "en": {ID: "en"}, "ru": {ID: "ru", Fallback: "en"}, }, }, wantTarget: &locales.Locale{ID: "ru", Fallback: "en"}, wantFallback: &locales.Locale{ID: "en"}, }, { name: "Success fallback no fallback", localizer: &Localizer{ localeID: "ru", localesKV: map[string]*locales.Locale{ "ru": {ID: "ru", Fallback: "en"}, "default": {ID: "default"}, }, }, wantTarget: &locales.Locale{ID: "ru", Fallback: "en"}, wantFallback: &locales.Locale{ID: "default"}, }, { name: "Fail fallback no fallback", localizer: &Localizer{ localeID: "ru", localesKV: map[string]*locales.Locale{ "ru": {ID: "ru", Fallback: "en"}, }, }, wantErr: true, }, { name: "Fail target nil", localizer: &Localizer{ localeID: "ru", localesKV: map[string]*locales.Locale{ "ru": nil, }, }, wantErr: true, }, { name: "Fail target disabled", localizer: &Localizer{ localeID: "ru", localesKV: map[string]*locales.Locale{ "ru": {ID: "ru", Fallback: "en", Disabled: true}, "default": {ID: "default"}, }, }, wantErr: true, }, { name: "Success fallback disabled", localizer: &Localizer{ localeID: "ru", localesKV: map[string]*locales.Locale{ "en": {ID: "en", Disabled: true}, "ru": {ID: "ru", Fallback: "en"}, "default": {ID: "default"}, }, }, wantTarget: &locales.Locale{ID: "ru", Fallback: "en"}, wantFallback: &locales.Locale{ID: "default"}, }, { name: "Fail target no publish", localizer: &Localizer{ localeID: "ru", localesKV: map[string]*locales.Locale{ "ru": {ID: "ru", Fallback: "en", NoPublish: true}, "default": {ID: "default"}, }, }, wantErr: true, }, { name: "Success fallback no publish", localizer: &Localizer{ localeID: "ru", localesKV: map[string]*locales.Locale{ "en": {ID: "en", NoPublish: true}, "ru": {ID: "ru", Fallback: "en"}, "default": {ID: "default"}, }, }, wantTarget: &locales.Locale{ID: "ru", Fallback: "en"}, wantFallback: &locales.Locale{ID: "en", NoPublish: true}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { gotTarget, gotFallback, err := tt.localizer.getTargetAndFallBackLocales() if tt.wantErr { require.Error(t, err) return } require.NoError(t, err) assert.Equal(t, tt.wantTarget, gotTarget) assert.Equal(t, tt.wantFallback, gotFallback) }) } }