Repository: jhillyerd/enmime
Pull request #346 (2024-08-31 21:36:03)

chore: resolve govet dynamic fmt string warning
Signed-off-by: James Hillyerd <james@hillyerd.com>



Patch:
diff --git a/envelope.go b/envelope.go
index bfade4f..db11457 100644
--- a/envelope.go
+++ b/envelope.go
@@ -198,16 +198,14 @@ func (p Parser) EnvelopeFromPart(root *Part) (*Envelope, error) {
 	// Down-convert HTML to text if necessary
 	if e.Text == "" && e.HTML != "" {
 		// We always warn when this happens
-		e.Root.addWarning(
-			ErrorPlainTextFromHTML,
-			"Message did not contain a text/plain part")
+		e.Root.addWarning(ErrorPlainTextFromHTML, "Message did not contain a text/plain part")
 
 		if !p.disableTextConversion {
 			var err error
 			if e.Text, err = html2text.FromString(e.HTML); err != nil {
 				e.Text = "" // Down-conversion shouldn't fail
 				p := e.Root.BreadthMatchFirst(matchHTMLBodyPart)
-				p.addError(ErrorPlainTextFromHTML, "Failed to downconvert HTML: %v", err)
+				p.addErrorf(ErrorPlainTextFromHTML, "Failed to downconvert HTML: %v", err)
 			}
 		}
 	}
diff --git a/error.go b/error.go
index 9f819b3..afbf844 100644
--- a/error.go
+++ b/error.go
@@ -54,8 +54,13 @@ func (e *Error) String() string {
 	return e.Error()
 }
 
-// addWarning builds a severe Error and appends to the Part error slice.
-func (p *Part) addError(name string, detailFmt string, args ...interface{}) {
+// addError builds a severe Error and appends to the Part error slice.
+func (p *Part) addError(name string, detail string) {
+	p.addProblem(&Error{name, detail, true})
+}
+
+// addErrorf builds a severe Error and appends to the Part error slice.
+func (p *Part) addErrorf(name string, detailFmt string, args ...interface{}) {
 	p.addProblem(&Error{
 		name,
 		fmt.Sprintf(detailFmt, args...),
@@ -64,7 +69,12 @@ func (p *Part) addError(name string, detailFmt string, args ...interface{}) {
 }
 
 // addWarning builds a non-severe Error and appends to the Part error slice.
-func (p *Part) addWarning(name string, detailFmt string, args ...interface{}) {
+func (p *Part) addWarning(name string, detail string) {
+	p.addProblem(&Error{name, detail, false})
+}
+
+// addWarningf builds a non-severe Error and appends to the Part error slice.
+func (p *Part) addWarningf(name string, detailFmt string, args ...interface{}) {
 	p.addProblem(&Error{
 		name,
 		fmt.Sprintf(detailFmt, args...),
@@ -97,9 +107,9 @@ type partErrorCollector struct {
 }
 
 func (p *partErrorCollector) AddError(name string, detailFmt string, args ...any) {
-	p.part.addError(name, detailFmt, args...)
+	p.part.addErrorf(name, detailFmt, args...)
 }
 
 func (p *partErrorCollector) AddWarning(name string, detailFmt string, args ...any) {
-	p.part.addWarning(name, detailFmt, args...)
+	p.part.addWarningf(name, detailFmt, args...)
 }
diff --git a/part.go b/part.go
index d2020c6..9e72ea4 100644
--- a/part.go
+++ b/part.go
@@ -129,7 +129,7 @@ func (p *Part) setupHeaders(r *bufio.Reader, defaultContentType string) error {
 		return err
 	}
 	for i := range minvalidParams {
-		p.addWarning(
+		p.addWarningf(
 			ErrorMalformedHeader,
 			"Content-Type header has malformed parameter %q",
 			minvalidParams[i])
@@ -171,7 +171,7 @@ func (p *Part) readPartContent(r io.Reader, readPartErrorPolicy ReadPartErrorPol
 	buf, err := io.ReadAll(r)
 	if err != nil {
 		if readPartErrorPolicy != nil && readPartErrorPolicy(p, err) {
-			p.addWarning(ErrorMalformedChildPart, "partial content: %s", err.Error())
+			p.addWarningf(ErrorMalformedChildPart, "partial content: %s", err.Error())
 			return buf, nil
 		}
 		return nil, err
@@ -211,7 +211,7 @@ func (p *Part) convertFromDetectedCharset(r io.Reader, readPartErrorPolicy ReadP
 	case nil:
 		// Carry on
 	default:
-		p.addWarning(ErrorCharsetDeclaration, "charset could not be detected: %v", err)
+		p.addWarningf(ErrorCharsetDeclaration, "charset could not be detected: %v", err)
 	}
 
 	if cs == nil || cs.Confidence < minCharsetConfidence || len(bytes.Runes(buf)) < p.parser.minCharsetDetectRunes {
@@ -221,7 +221,7 @@ func (p *Part) convertFromDetectedCharset(r io.Reader, readPartErrorPolicy ReadP
 
 	// Confidence exceeded our threshold, use detected character set.
 	if p.Charset != "" && !strings.EqualFold(cs.Charset, p.Charset) {
-		p.addWarning(ErrorCharsetDeclaration,
+		p.addWarningf(ErrorCharsetDeclaration,
 			"declared charset %q, detected %q, confidence %d",
 			p.Charset, cs.Charset, cs.Confidence)
 	}
@@ -247,7 +247,7 @@ func (p *Part) convertFromStatedCharset(r io.Reader) io.Reader {
 	reader, err := coding.NewCharsetReader(p.Charset, r)
 	if err != nil {
 		// Failed to get a conversion reader.
-		p.addWarning(ErrorCharsetConversion, "failed to get reader for charset %q: %v", p.Charset, err)
+		p.addWarningf(ErrorCharsetConversion, "failed to get reader for charset %q: %v", p.Charset, err)
 	} else {
 		return reader
 	}
@@ -261,7 +261,7 @@ func (p *Part) convertFromStatedCharset(r io.Reader) io.Reader {
 		reader, err = coding.NewCharsetReader(p.Charset, r)
 		if err != nil {
 			// Failed to get a conversion reader.
-			p.addWarning(ErrorCharsetConversion, "failed to get reader for charset %q: %v", p.Charset, err)
+			p.addWarningf(ErrorCharsetConversion, "failed to get reader for charset %q: %v", p.Charset, err)
 		} else {
 			return reader
 		}
@@ -297,7 +297,7 @@ func (p *Part) decodeContent(r io.Reader, readPartErrorPolicy ReadPartErrorPolic
 	default:
 		// Unknown encoding.
 		validEncoding = false
-		p.addWarning(
+		p.addWarningf(
 			ErrorContentEncoding,
 			"Unrecognized Content-Transfer-Encoding type %q",
 			encoding)
@@ -324,7 +324,7 @@ func (p *Part) decodeContent(r io.Reader, readPartErrorPolicy ReadPartErrorPolic
 	}
 	// Set empty content-type error.
 	if p.ContentType == "" {
-		p.addWarning(
+		p.addWarningf(
 			ErrorMissingContentType, "content-type is empty for part id: %s", p.PartID)
 	}
 	return nil
@@ -429,7 +429,7 @@ func parseParts(parent *Part, reader *bufio.Reader) error {
 			return err
 		}
 		if br.unbounded {
-			parent.addWarning(ErrorMissingBoundary, "Boundary %q was not closed correctly",
+			parent.addWarningf(ErrorMissingBoundary, "Boundary %q was not closed correctly",
 				parent.Boundary)
 		}
 		if !next {
@@ -448,7 +448,7 @@ func parseParts(parent *Part, reader *bufio.Reader) error {
 		bbr := bufio.NewReader(br)
 		if err = p.setupHeaders(bbr, ""); err != nil {
 			if p.parser.skipMalformedParts {
-				parent.addError(ErrorMalformedChildPart, "read header: %s", err.Error())
+				parent.addErrorf(ErrorMalformedChildPart, "read header: %s", err.Error())
 				continue
 			}
 
@@ -460,7 +460,7 @@ func parseParts(parent *Part, reader *bufio.Reader) error {
 			// Content is text or data, decode it.
 			if err = p.decodeContent(bbr, p.parser.readPartErrorPolicy); err != nil {
 				if p.parser.skipMalformedParts {
-					parent.addError(ErrorMalformedChildPart, "decode content: %s", err.Error())
+					parent.addErrorf(ErrorMalformedChildPart, "decode content: %s", err.Error())
 					continue
 				}
 				return err
@@ -473,7 +473,7 @@ func parseParts(parent *Part, reader *bufio.Reader) error {
 		// Content is another multipart.
 		if err = parseParts(p, bbr); err != nil {
 			if p.parser.skipMalformedParts {
-				parent.addError(ErrorMalformedChildPart, "parse parts: %s", err.Error())
+				parent.addErrorf(ErrorMalformedChildPart, "parse parts: %s", err.Error())
 				continue
 			}
 			return err


Test patch:
diff --git a/error_test.go b/error_test.go
index f24c86d..cefee0a 100644
--- a/error_test.go
+++ b/error_test.go
@@ -37,7 +37,7 @@ func TestErrorStringConversion(t *testing.T) {
 
 func TestErrorAddError(t *testing.T) {
 	p := NewPart("text/plain")
-	p.addError(ErrorMalformedHeader, "1 %v %q", 2, "three")
+	p.addErrorf(ErrorMalformedHeader, "1 %v %q", 2, "three")
 
 	if len(p.Errors) != 1 {
 		t.Fatal("len(p.Errors) ==", len(p.Errors), ", want: 1")
@@ -58,7 +58,7 @@ func TestErrorAddError(t *testing.T) {
 
 func TestErrorAddWarning(t *testing.T) {
 	p := NewPart("text/plain")
-	p.addWarning(ErrorMalformedHeader, "1 %v %q", 2, "three")
+	p.addWarningf(ErrorMalformedHeader, "1 %v %q", 2, "three")
 
 	if len(p.Errors) != 1 {
 		t.Fatal("len(p.Errors) ==", len(p.Errors), ", want: 1")