Browse Source

go-i18n: some tests now pass with localized errors.

Frederic G. MARAND 5 years ago
parent
commit
1d2799ea95
6 changed files with 84 additions and 13 deletions
  1. 1 2
      .idea/runConfigurations/Test_domain.xml
  2. 2 2
      domain/domain_api_testing.go
  3. 26 7
      domain/errors.go
  4. 52 0
      domain/errors_test.go
  5. 1 1
      domain/short_url.go
  6. 2 1
      go.mod

+ 1 - 2
.idea/runConfigurations/Test_domain.xml

@@ -6,8 +6,7 @@
     <kind value="PACKAGE" />
     <package value="code.osinet.fr/fgm/kurz/domain" />
     <directory value="$PROJECT_DIR$/" />
-    <filePath value="$PROJECT_DIR$/" />
-    <pattern value="./..." />
+    <filePath value="$PROJECT_DIR$/domain/errors_test.go" />
     <method v="2" />
   </configuration>
 </component>

+ 2 - 2
domain/domain_api_testing.go

@@ -5,7 +5,7 @@ type MockShortRepo map[ShortURL]TargetURL
 func (sr MockShortRepo) GetTarget(su ShortURL) (tu TargetURL, err error) {
 	tu, ok := sr[su]
 	if !ok {
-		err = MakeError(ShortNotFound, "")
+		err = MakeError(nil, ShortNotFound.Other, "")
 	}
 	return
 }
@@ -25,7 +25,7 @@ func (tr MockTargetRepo) GetShort(tu TargetURL) (su ShortURL, isNew bool, err er
 		tr.Data[tu] = su
 		isNew = true
 	} else {
-		err = MakeError(ShortNotCreated, "")
+		err = MakeError(nil, ShortNotCreated.Other, "")
 	}
 
 	return

+ 26 - 7
domain/errors.go

@@ -2,6 +2,7 @@ package domain
 
 import (
 	"errors"
+	"fmt"
 
 	"github.com/nicksnyder/go-i18n/v2/i18n"
 )
@@ -40,13 +41,24 @@ type Error struct {
 
 // MakeError creates a localized error instance, ready to print.
 func MakeError(l *i18n.Localizer, kind ErrorKind, detail string) Error {
-	format := i18n.Message{
-		ID:          "web.error.format",
-		Description: "The format for errors",
-		One:         "{.Kind}: {.Detail}",
-	}
 	var message string
 
+	// Support errors with a localizer.
+	if l == nil {
+		s := ErrorMessages[kind].Other
+		var e error
+		if detail != "" {
+			e = errors.New(fmt.Sprintf("%s: %s", s, detail))
+		} else {
+			e = errors.New(s)
+		}
+		err := Error{
+			Kind:  kind,
+			error: e,
+		}
+		return err
+	}
+
 	if len(detail) == 0 {
 		message = l.MustLocalize(&i18n.LocalizeConfig{
 			MessageID: ErrorMessages[kind].ID,
@@ -55,7 +67,7 @@ func MakeError(l *i18n.Localizer, kind ErrorKind, detail string) Error {
 		em, ok := ErrorMessages[kind]
 		if !ok {
 			em = i18n.Message{
-				ID: "error.dynamic",
+				ID:          "error.dynamic",
 				Description: "This is an unplanned error generated on the fly from details. It should be replaced",
 			}
 		}
@@ -64,11 +76,18 @@ func MakeError(l *i18n.Localizer, kind ErrorKind, detail string) Error {
 			MessageID:      em.ID,
 		})
 		message = l.MustLocalize(&i18n.LocalizeConfig{
-			DefaultMessage: &format,
+			DefaultMessage: &i18n.Message{
+				ID:          "web.error.format",
+				Description: "The format for errors",
+				One:         "{.Kind}: {.Detail}",
+				LeftDelim:   "{",
+				RightDelim:  "}",
+			},
 			TemplateData: map[string]string{
 				"Kind":   localizedKind,
 				"Detail": detail,
 			},
+			PluralCount: 1,
 		})
 	}
 

+ 52 - 0
domain/errors_test.go

@@ -0,0 +1,52 @@
+package domain
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+	"golang.org/x/text/language"
+)
+
+/*
+TestMakeErrorHappy tests localization of a known error.
+*/
+func TestMakeErrorHappy(t *testing.T) {
+	frNoError := i18n.Message{
+		ID:    NoError.ID,
+		Other: "Pas d'erreur",
+	}
+	bundle := &i18n.Bundle{DefaultLanguage: language.English}
+	bundle.AddMessages(language.English, &NoError)
+	bundle.AddMessages(language.French, &frNoError)
+
+	type testPass struct {
+		tag      string
+		error    i18n.Message
+		details  string
+		expected string
+	}
+	passes := []testPass{
+		{language.English.String(), NoError, "", NoError.Other},
+		{language.English.String(), NoError, "details", NoError.Other + ": details"},
+		{language.French.String(), frNoError, "", frNoError.Other},
+		{language.French.String(), frNoError, "details", frNoError.Other + ": details"},
+	}
+	for _, pass := range passes {
+		var name string
+		if pass.details == "" {
+			name =fmt.Sprintf("%s/<no details>", pass.tag)
+		} else {
+			name =fmt.Sprintf("%s/%s", pass.tag, pass.details)
+		}
+		t.Run(name, func(t *testing.T) {
+			localizer := i18n.NewLocalizer(bundle, pass.tag)
+			err := MakeError(localizer, pass.error.ID, pass.details)
+			expected := pass.expected
+			if err.Error() != expected {
+				t.Errorf("Localized \"%s\" version (%v) does not match expected value (%v)\n",
+					pass.tag, err.Error(), expected)
+			}
+		})
+	}
+}

+ 1 - 1
domain/short_url.go

@@ -20,7 +20,7 @@ MakeShortURL creates a ShortURL instance from a given RedirectURL/target pair.
 func NewUnspecifiedShortURL(target TargetURL) (ShortURL, error) {
 	var su ShortURL
 	if target.IsEmpty() {
-		return su, MakeError(TargetInvalid, "empty URL")
+		return su, MakeError(nil, TargetInvalid.Other, "empty URL")
 	}
 
 	// FIXME: will cause collisions.

+ 2 - 1
go.mod

@@ -2,11 +2,12 @@ module code.osinet.fr/fgm/kurz
 
 require (
 	github.com/BurntSushi/toml v0.3.1 // indirect
+	github.com/davecgh/go-spew v1.1.1
 	github.com/go-sql-driver/mysql v1.4.0
 	github.com/gorilla/mux v1.6.2
 	github.com/gorilla/sessions v1.1.3
 	github.com/inconshreveable/mousetrap v1.0.0 // indirect
-	github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.6 // indirect
+	github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.6
 	github.com/pressly/goose v2.4.3+incompatible
 	github.com/spf13/cast v1.3.0
 	github.com/spf13/cobra v0.0.3