aboutsummaryrefslogtreecommitdiffstats
path: root/filters/wrap_test.go
diff options
context:
space:
mode:
authorRobin Jarry <robin@jarry.cc>2022-12-01 20:17:04 +0100
committerRobin Jarry <robin@jarry.cc>2022-12-05 17:25:12 +0100
commitc9524d265793775e4c3e326c7191471d982c1e66 (patch)
treee6d3cee41885f94dd3ce00c09c774536af748f1d /filters/wrap_test.go
parentbe8154d1a77c9dce313a94e51e1b5bea7a21d7b7 (diff)
downloadaerc-c9524d265793775e4c3e326c7191471d982c1e66.tar.gz
filters: add wrap utility written in go
I had started writing this as an awk script but quickly got stuck with obscure code which did not even work properly. I jumped the gun and re did it in go. Bonus, we will not have MacOS's 1987 BSD awk issues. On the other hand, instead of a 20.0K awk script, we now have a 2.2M static go binary. If this makes people scream, I challenge them to do that with BSD awk :) Basically, this takes text from stdin or from a file and wraps long lines on word boundaries. It takes care of not breaking up email quotes nor list items (numbered as well). Also, it is conservative by default and only wraps long lines and lines that end with a space (indicating a format=flowed message). If the AERC_SUBJECT environment variable is defined and contains the word PATCH, the text is not modified at all (i.e. wrap behaves as cat(1)). There are a few command line options to control behavior: Usage of ./wrap: -f string read from file instead of stdin -l int minimum percentage of letters in a line to be considered a paragaph (default 50) -r reflow all paragraphs even if no trailing space -w int preferred wrap margin (default 80) Update docs, makefile and default config file with examples. Add a torture test to ensure it works as expected. Signed-off-by: Robin Jarry <robin@jarry.cc> Tested-by: Bence Ferdinandy <bence@ferdinandy.com>
Diffstat (limited to 'filters/wrap_test.go')
-rw-r--r--filters/wrap_test.go212
1 files changed, 212 insertions, 0 deletions
diff --git a/filters/wrap_test.go b/filters/wrap_test.go
new file mode 100644
index 00000000..f8d82cbe
--- /dev/null
+++ b/filters/wrap_test.go
@@ -0,0 +1,212 @@
+package main
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "testing"
+)
+
+type vector struct {
+ name string
+ in string
+ out string
+ width int
+ reflow bool
+ ratio int
+}
+
+var vectors = []vector{
+ {
+ name: "simple",
+ in: `long line that exceeds margin by many words
+`,
+ width: 30,
+ reflow: false,
+ ratio: 50,
+ out: `long line that exceeds margin
+by many words
+`,
+ },
+ {
+ name: "two-paragraphs",
+ in: `this is one long paragraph
+this is another long one
+`,
+ width: 20,
+ reflow: false,
+ ratio: 50,
+ out: `this is one long
+paragraph
+this is another
+long one
+`,
+ },
+ {
+ name: "reflow",
+ in: `this is one long paragraph
+this is another long one
+`,
+ width: 20,
+ reflow: true,
+ ratio: 50,
+ out: `this is one long
+paragraph this is
+another long one
+`,
+ },
+ {
+ name: "quotes",
+ in: `Let's play with quotes:
+
+>> Hi there how are you doing?
+> Great thanks
+
+How rude.
+
+>> Fantastic. Let's go wrap some words.
+`,
+ width: 20,
+ reflow: false,
+ ratio: 50,
+ out: `Let's play with
+quotes:
+
+>> Hi there how are
+>> you doing?
+> Great thanks
+
+How rude.
+
+>> Fantastic. Let's
+>> go wrap some
+>> words.
+`,
+ },
+ {
+ name: "ascii-art",
+ in: `This is a nice drawing, isn't it?
+
++-------------------+
+| foobaz |
++-------------------+
+ |
+ |
++-------------------+
+| foobar |
++-------------------+
+`,
+ width: 15,
+ ratio: 50,
+ reflow: true,
+ out: `This is a nice
+drawing, isn't
+it?
+
++-------------------+
+| foobaz |
++-------------------+
+ |
+ |
++-------------------+
+| foobar |
++-------------------+
+`,
+ },
+ {
+ name: "list-items",
+ in: `Shopping list:
+
+ - milk
+ - chocolate
+ - cookies (please, with nuts)
+`,
+ width: 20,
+ reflow: false,
+ ratio: 50,
+ out: `Shopping list:
+
+ - milk
+ - chocolate
+ - cookies
+ (please, with
+ nuts)
+`,
+ },
+ {
+ name: "list-items-reflow",
+ in: `Shopping list:
+
+ * milk
+ * chocolate
+ * cookies
+ (please,
+ with nuts)
+`,
+ width: 100,
+ reflow: true,
+ ratio: 30,
+ out: `Shopping list:
+
+ * milk
+ * chocolate
+ * cookies (please, with nuts)
+`,
+ },
+ {
+ name: "long-url",
+ in: `Please follow this ugly link:
+http://foobaz.org/xapapzolmkdmldfk-fldskjflsk-cisjoij/onoes.jsp?xxx=2&yyy=3
+`,
+ width: 20,
+ reflow: true,
+ ratio: 50,
+ out: `Please follow this
+ugly link:
+http://foobaz.org/xapapzolmkdmldfk-fldskjflsk-cisjoij/onoes.jsp?xxx=2&yyy=3
+`,
+ },
+ {
+ name: "format=flowed",
+ in: "Oh, \nI'm \nso \nhip \nI \nuse \nformat=flowed.\n",
+ width: 30,
+ reflow: false,
+ ratio: 50,
+ out: "Oh, I'm so hip I use\nformat=flowed.\n",
+ },
+ {
+ name: "non-ascii",
+ in: `Lorem ççççç ççççç ççç ççççç çç ççç ççççç çççççççç ççç çç ççççç ççççççççççç ççççç
+
+Lorem жжжжж жжжжж жжж жжжжж жж жжж жжжжж жжжжжжжж жжж жж жжжжж жжжжжжжжжжж жжжжж жжжжжжжж
+`,
+ width: 40,
+ reflow: false,
+ ratio: 50,
+ out: `Lorem ççççç ççççç ççç ççççç çç ççç
+ççççç çççççççç ççç çç ççççç ççççççççççç
+ççççç
+
+Lorem жжжжж жжжжж жжж жжжжж жж жжж
+жжжжж жжжжжжжж жжж жж жжжжж жжжжжжжжжжж
+жжжжж жжжжжжжж
+`,
+ },
+}
+
+func TestWrap(t *testing.T) {
+ for _, vec := range vectors {
+ t.Run(vec.name, func(t *testing.T) {
+ r := bytes.NewReader([]byte(vec.in))
+ var buf bytes.Buffer
+ err := wrap(r, &buf, vec.width, vec.reflow, vec.ratio)
+ if err != nil && !errors.Is(err, io.EOF) {
+ t.Fatalf("[%s]: %v", vec.name, err)
+ }
+ if buf.String() != vec.out {
+ t.Errorf("[%s] invalid format:\n%q\nexpected\n%q",
+ vec.name, buf.String(), vec.out)
+ }
+ })
+ }
+}