unicode/norm: correct use of ErrShortDst

In some cases the ErrShortDst error was
eroneously overriden by ErrShortSrc.

Fixes golang/go#24170.

Change-Id: I07dd160de045474e8e38506b6793a1da0df6283d
Reviewed-on: https://go-review.googlesource.com/c/145558
Run-TryBot: Marcel van Lohuizen <mpvl@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ross Light <light@google.com>
diff --git a/unicode/norm/transform.go b/unicode/norm/transform.go
index 9f47efb..a1d366a 100644
--- a/unicode/norm/transform.go
+++ b/unicode/norm/transform.go
@@ -18,7 +18,6 @@
 // Users should either catch ErrShortDst and allow dst to grow or have dst be at
 // least of size MaxTransformChunkSize to be guaranteed of progress.
 func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
-	n := 0
 	// Cap the maximum number of src bytes to check.
 	b := src
 	eof := atEOF
@@ -27,13 +26,14 @@
 		eof = false
 		b = b[:ns]
 	}
-	i, ok := formTable[f].quickSpan(inputBytes(b), n, len(b), eof)
-	n += copy(dst[n:], b[n:i])
+	i, ok := formTable[f].quickSpan(inputBytes(b), 0, len(b), eof)
+	n := copy(dst, b[:i])
 	if !ok {
 		nDst, nSrc, err = f.transform(dst[n:], src[n:], atEOF)
 		return nDst + n, nSrc + n, err
 	}
-	if n < len(src) && !atEOF {
+
+	if err == nil && n < len(src) && !atEOF {
 		err = transform.ErrShortSrc
 	}
 	return n, n, err
@@ -79,7 +79,7 @@
 		nSrc += n
 		nDst += n
 		if ok {
-			if n < rb.nsrc && !atEOF {
+			if err == nil && n < rb.nsrc && !atEOF {
 				err = transform.ErrShortSrc
 			}
 			return nDst, nSrc, err
diff --git a/unicode/norm/transform_test.go b/unicode/norm/transform_test.go
index d596ff3..2690fc3 100644
--- a/unicode/norm/transform_test.go
+++ b/unicode/norm/transform_test.go
@@ -47,6 +47,13 @@
 		{NFD, "a\u0300", "", false, 4, transform.ErrShortSrc},
 		{NFC, "ö", "", false, 3, transform.ErrShortSrc},
 
+		{NFD, "abc", "", false, 1, transform.ErrShortDst},
+		{NFC, "abc", "", false, 1, transform.ErrShortDst},
+		{NFC, "abc", "a", false, 2, transform.ErrShortDst},
+		{NFD, "éfff", "", false, 2, transform.ErrShortDst},
+		{NFC, "e\u0301fffff", "\u00e9fff", false, 6, transform.ErrShortDst},
+		{NFD, "ééééé", "e\u0301e\u0301e\u0301", false, 15, transform.ErrShortDst},
+
 		{NFC, "a\u0300", "", true, 1, transform.ErrShortDst},
 		// Theoretically could fit, but won't due to simplified checks.
 		{NFC, "a\u0300", "", true, 2, transform.ErrShortDst},
@@ -62,14 +69,16 @@
 	}
 	b := make([]byte, 100)
 	for i, tt := range tests {
-		nDst, _, err := tt.f.Transform(b[:tt.dstSize], []byte(tt.in), tt.eof)
-		out := string(b[:nDst])
-		if out != tt.out || err != tt.err {
-			t.Errorf("%d: was %+q (%v); want %+q (%v)", i, out, err, tt.out, tt.err)
-		}
-		if want := tt.f.String(tt.in)[:nDst]; want != out {
-			t.Errorf("%d: incorrect normalization: was %+q; want %+q", i, out, want)
-		}
+		t.Run(fmt.Sprintf("%d:%s", i, tt.in), func(t *testing.T) {
+			nDst, _, err := tt.f.Transform(b[:tt.dstSize], []byte(tt.in), tt.eof)
+			out := string(b[:nDst])
+			if out != tt.out || err != tt.err {
+				t.Errorf("was %+q (%v); want %+q (%v)", out, err, tt.out, tt.err)
+			}
+			if want := tt.f.String(tt.in)[:nDst]; want != out {
+				t.Errorf("incorrect normalization: was %+q; want %+q", out, want)
+			}
+		})
 	}
 }