diff options
Diffstat (limited to 'cnmfmt/cnmfmt_test.go')
-rw-r--r-- | cnmfmt/cnmfmt_test.go | 457 |
1 files changed, 457 insertions, 0 deletions
diff --git a/cnmfmt/cnmfmt_test.go b/cnmfmt/cnmfmt_test.go new file mode 100644 index 0000000..89a40a9 --- /dev/null +++ b/cnmfmt/cnmfmt_test.go @@ -0,0 +1,457 @@ +package cnmfmt + +import ( + "bytes" + "io" + "strings" + "testing" + + "contnet.org/lib/cnm-go" +) + +var parseTests = map[string]Text{ + "\\nfoo\nbar\\": Text{[]Span{ + Span{Format{}, "\nfoo bar\\"}, + }}, + "**foo": Text{[]Span{ + Span{Format{Bold: true}, "foo"}, + }}, + "//foo": Text{[]Span{ + Span{Format{Italic: true}, "foo"}, + }}, + "__foo": Text{[]Span{ + Span{Format{Underline: true}, "foo"}, + }}, + "``foo": Text{[]Span{ + Span{Format{Monospace: true}, "foo"}, + }}, + "foo*bar": Text{[]Span{ + Span{Format{}, "foo*bar"}, + }}, + "foo*": Text{[]Span{ + Span{Format{}, "foo*"}, + }}, + "foo**": Text{[]Span{ + Span{Format{}, "foo"}, + }}, + "foo***": Text{[]Span{ + Span{Format{}, "foo"}, + Span{Format{Bold: true}, "*"}, + }}, + "foo****": Text{[]Span{ + Span{Format{}, "foo"}, + }}, + "*foo": Text{[]Span{ + Span{Format{}, "*foo"}, + }}, + "****foo": Text{[]Span{ + Span{Format{}, "foo"}, + }}, + "******foo": Text{[]Span{ + Span{Format{Bold: true}, "foo"}, + }}, + "foo ** bar": Text{[]Span{ + Span{Format{}, "foo "}, + Span{Format{Bold: true}, " bar"}, + }}, + "foo** bar": Text{[]Span{ + Span{Format{}, "foo"}, + Span{Format{Bold: true}, " bar"}, + }}, + "foo **bar": Text{[]Span{ + Span{Format{}, "foo "}, + Span{Format{Bold: true}, "bar"}, + }}, + "foo ** bar ** baz": Text{[]Span{ + Span{Format{}, "foo "}, + Span{Format{Bold: true}, " bar "}, + Span{Format{}, " baz"}, + }}, + "foo ** bar** baz": Text{[]Span{ + Span{Format{}, "foo "}, + Span{Format{Bold: true}, " bar"}, + Span{Format{}, " baz"}, + }}, + "**__**foo": Text{[]Span{ + Span{Format{Underline: true}, "foo"}, + }}, + "***": Text{[]Span{ + Span{Format{Bold: true}, "*"}, + }}, + "*\\**": Text{[]Span{ + Span{Format{}, "***"}, + }}, + "\\*": Text{[]Span{ + Span{Format{}, "*"}, + }}, + "\\*\\*": Text{[]Span{ + Span{Format{}, "**"}, + }}, + "\\**": Text{[]Span{ + Span{Format{}, "**"}, + }}, + "*\\*": Text{[]Span{ + Span{Format{}, "**"}, + }}, + "\\": Text{[]Span{ + Span{Format{}, "\\"}, + }}, + "\\\\": Text{[]Span{ + Span{Format{}, "\\"}, + }}, + " ** // `` ": Text{[]Span{ + Span{Format{Bold: true}, " "}, + Span{Format{Bold: true, Italic: true}, " "}, + }}, + "**": Text{[]Span{}}, + "**``__//foo": Text{[]Span{ + Span{Format{Bold: true, Monospace: true, Underline: true, Italic: true}, "foo"}, + }}, + "**foo//bar**baz": Text{[]Span{ + Span{Format{Bold: true}, "foo"}, + Span{Format{Bold: true, Italic: true}, "bar"}, + Span{Format{Italic: true}, "baz"}, + }}, + "@@foo": Text{[]Span{ + Span{Format{Link: "foo"}, ""}, + }}, + "@@foo@@": Text{[]Span{ + Span{Format{Link: "foo"}, ""}, + }}, + "@@foo bar@@": Text{[]Span{ + Span{Format{Link: "foo"}, "bar"}, + }}, + "@@ foo": Text{[]Span{ + Span{Format{Link: "foo"}, ""}, + }}, + "@@foo ": Text{[]Span{ + Span{Format{Link: "foo"}, ""}, + }}, + "@@foo\\": Text{[]Span{ + Span{Format{Link: "foo\\"}, ""}, + }}, + "@@foo \\": Text{[]Span{ + Span{Format{Link: "foo"}, "\\"}, + }}, + "@@foo \\\\": Text{[]Span{ + Span{Format{Link: "foo"}, "\\"}, + }}, + "@@foo@": Text{[]Span{ + Span{Format{Link: "foo@"}, ""}, + }}, + "@@foo\\@@": Text{[]Span{ + Span{Format{Link: "foo@@"}, ""}, + }}, + "@@f\\\\o\\o\\n @": Text{[]Span{ + Span{Format{Link: "f\\o\\o\n"}, "@"}, + }}, + "@@http://example.com foo **bar @@baz**": Text{[]Span{ + Span{Format{Link: "http://example.com"}, "foo "}, + Span{Format{Bold: true, Link: "http://example.com"}, "bar "}, + Span{Format{Bold: true}, "baz"}, + }}, + "//@@http://example.com foo //bar @@": Text{[]Span{ + Span{Format{Italic: true, Link: "http://example.com"}, "foo "}, + Span{Format{Link: "http://example.com"}, "bar "}, + }}, + "__\\ asd \\ zxc\\ ": Text{[]Span{ + Span{Format{Underline: true, Monospace: false}, " asd zxc "}, + }}, + "@@/ test/@@": Text{[]Span{ + Span{Format{Link: "/"}, "test/"}, + }}, + "@@/ /test@@": Text{[]Span{ + Span{Format{Link: "/"}, "/test"}, + }}, + "/": Text{[]Span{ + Span{Format{}, "/"}, + }}, + "test/**": Text{[]Span{ + Span{Format{}, "test/"}, + }}, + "//test/": Text{[]Span{ + Span{Format{Italic: true}, "test/"}, + }}, + "/**test": Text{[]Span{ + Span{Format{}, "/"}, + Span{Format{Bold: true}, "test"}, + }}, +} + +func TestParseParagraph(t *testing.T) { + for k, v := range parseTests { + t.Run(k, func(t *testing.T) { + txt := ParseParagraph(k) + if !textEqual(txt, v) { + t.Errorf("ParseParagraph(%q):\nexpected: %#v\n got: %#v", k, v, txt) + } + }) + } +} + +func TestParse(t *testing.T) { + for k, v := range parseTests { + t.Run(k, func(t *testing.T) { + txts := Parse(k) + if len(txts) != 1 || !textEqual(txts[0], v) { + t.Errorf("Parse(%q):\nexpected: %#v\n got: %#v", k, []Text{v}, txts) + } + }) + } +} + +func textEqual(a, b Text) bool { + if len(a.Spans) != len(b.Spans) { + return false + } + for i := range a.Spans { + if a.Spans[i] != b.Spans[i] { + return false + } + } + return true +} + +var escapeTests = map[string]string{ + "\n\r\t\v\x00": "\\n\\r\\t\v\\x00", + "@@!!##__//__``**": "\\@\\@!!##\\_\\_\\/\\/\\_\\_\\`\\`\\*\\*", + `foo\@\@bar`: `foo\\\@\\\@bar`, +} + +func TestEscape(t *testing.T) { + for k, v := range escapeTests { + t.Run(k, func(t *testing.T) { + if e := Escape(k); e != v { + t.Errorf("Escape(%q): expected %q, got %q", k, v, e) + } + }) + } +} + +var parseTextTests = map[string]TextFmtContents{ + "foo ** bar\nbaz\n\n\nquux ** ": TextFmtContents{[]Text{ + Text{[]Span{ + Span{Format{}, "foo "}, + Span{Format{Bold: true}, " bar baz"}, + }}, + Text{[]Span{ + Span{Format{}, "quux "}, + }}, + }}, + + "\n": TextFmtContents{}, + + "foo": TextFmtContents{[]Text{ + Text{[]Span{ + Span{Format{}, "foo"}, + }}, + }}, + + "\n\n": TextFmtContents{}, + + "foo\n\t\t\t\t\nbar": TextFmtContents{[]Text{ + Text{[]Span{Span{Format{}, "foo"}}}, + Text{[]Span{Span{Format{}, "bar"}}}, + }}, + + "foo\n\t\t \f\r\t\nbar": TextFmtContents{[]Text{ + Text{[]Span{Span{Format{}, "foo"}}}, + Text{[]Span{Span{Format{}, "bar"}}}, + }}, + + `foo**bar\*\*baz\*\*quux**qweasd`: TextFmtContents{[]Text{Text{[]Span{ + Span{Format{}, "foo"}, + Span{Format{Bold: true}, "bar**baz**quux"}, + Span{Format{}, "qweasd"}, + }}}}, +} + +func TestParseTextFmt(t *testing.T) { + for k, v := range parseTextTests { + t.Run(k, func(t *testing.T) { + parser := cnm.NewParser(strings.NewReader(k)) + err := parser.Next() + if err != nil && err != io.EOF { + t.Fatalf("error parsing %q: %v", k, err) + } + content, err := parseTextFmt(parser, cnm.TopLevel) + if err != nil && err != io.EOF { + t.Fatalf("error parsing %q: %v", k, err) + } + tf, ok := content.(TextFmtContents) + if !ok { + t.Fatalf("%q: expected type %T, got %T", k, v, content) + } + if !paragraphsEqual(v.Paragraphs, tf.Paragraphs) { + t.Fatalf("%q:\nexpected: %#v\n got: %#v", k, v, tf) + } + txts := Parse(k) + if !paragraphsEqual(txts, v.Paragraphs) { + t.Fatalf("%q:\nexpected: %#v\n got: %#v", k, v.Paragraphs, txts) + } + }) + } +} + +func paragraphsEqual(a, b []Text) bool { + if len(a) != len(b) { + return false + } + for i := range a { + if !textEqual(a[i], b[i]) { + return false + } + } + return true +} + +var writeTests = map[string]TextFmtContents{ + "": TextFmtContents{}, + + "foo\n": TextFmtContents{[]Text{ + Text{[]Span{ + Span{Format{}, "foo"}, + }}, + }}, + + "**foo\n": TextFmtContents{[]Text{ + Text{[]Span{ + Span{Format{Bold: true}, "foo"}, + }}, + }}, + + "foo **bar baz\n\nquux\n": TextFmtContents{[]Text{ + Text{[]Span{ + Span{Format{}, "foo "}, + Span{Format{Bold: true}, "bar baz"}, + }}, + Text{[]Span{ + Span{Format{}, "quux"}, + }}, + }}, + + "foo**bar``baz**quux\n\n" + + "\\ __qwe\\ __//\\ asd \\ //``zxc``**\\ \n\n" + + "//@@http://example.com exa//mple@@ @@href text@@// test\n": TextFmtContents{[]Text{ + Text{[]Span{ + Span{Format{}, "foo"}, + Span{Format{Bold: true}, "bar"}, + Span{Format{Bold: true, Monospace: true}, "baz"}, + Span{Format{Monospace: true}, "quux"}, + }}, + Text{[]Span{ + Span{Format{}, " "}, + Span{Format{Underline: true}, "qwe "}, + Span{Format{Italic: true}, " asd "}, + Span{Format{Monospace: true}, "zxc"}, + Span{Format{Bold: true}, " "}, + }}, + Text{[]Span{ + Span{Format{Italic: true, Link: "http://example.com"}, "exa"}, + Span{Format{Link: "http://example.com"}, "mple"}, + Span{Format{}, " "}, + Span{Format{Link: "href"}, "text"}, + Span{Format{Italic: true}, " test"}, + }}, + }}, + + "foo**bar\\*\\*baz\\*\\*quux**qweasd\n": TextFmtContents{[]Text{Text{[]Span{ + Span{Format{}, "foo"}, + Span{Format{Bold: true}, "bar**baz**quux"}, + Span{Format{}, "qweasd"}, + }}}}, +} + +func TestWriteTextFmt(t *testing.T) { + for k, v := range writeTests { + t.Run(k, func(t *testing.T) { + var buf bytes.Buffer + err := v.WriteIndent(&buf, 0) + if err != nil { + t.Fatalf("WriteIndent error: %v", err) + } + w := buf.String() + t.Log("expected:\n" + k) + t.Log(" got:\n" + w) + if k != w { + t.Fatalf("WriteIndent: output did not match expected document:\nexpected: %q\n got: %q", k, w) + } + }) + } +} + +func TestWriteParseTextFmt(t *testing.T) { + for k, v := range writeTests { + t.Run(k, func(t *testing.T) { + var buf bytes.Buffer + err := v.WriteIndent(&buf, 0) + if err != nil { + t.Fatalf("WriteIndent error: %v", err) + } + w := buf.String() + + if w == "" { + w = "\n" + } + parser := cnm.NewParser(strings.NewReader(w)) + err = parser.Next() + if err != nil && err != io.EOF { + t.Fatalf("error parsing %q: %v", w, err) + } + content, err := parseTextFmt(parser, cnm.TopLevel) + if err != nil && err != io.EOF { + t.Fatalf("error parsing %q: %v", w, err) + } + tf, ok := content.(TextFmtContents) + if !ok { + t.Fatalf("%q: expected type %T, got %T", w, v, content) + } + if !paragraphsEqual(v.Paragraphs, tf.Paragraphs) { + t.Fatalf("%q:\nexpected: %#v\n got: %#v", k, v, tf) + } + }) + } +} + +func TestParseWriteTextFmt(t *testing.T) { + for k, v := range writeTests { + t.Run(k, func(t *testing.T) { + s := k + if s == "" { + s = "\n" + } + parser := cnm.NewParser(strings.NewReader(s)) + err := parser.Next() + if err != nil && err != io.EOF { + t.Fatalf("error parsing %q: %v", k, err) + } + + content, err := parseTextFmt(parser, cnm.TopLevel) + if err != nil && err != io.EOF { + t.Fatalf("error parsing %q: %v", k, err) + } + tf, ok := content.(TextFmtContents) + if !ok { + t.Fatalf("%q: expected type %T, got %T", k, v, content) + } + if !paragraphsEqual(tf.Paragraphs, v.Paragraphs) { + t.Fatalf("%q: expected %#v, got %#v", k, v, tf) + } + + var buf bytes.Buffer + err = tf.WriteIndent(&buf, 0) + if err != nil { + t.Fatalf("WriteIndent error: %v", err) + } + + w := buf.String() + /*if w == "\n" { + k = "" + }*/ + + if k != w { + t.Fatalf("%q:\nexpected: %#v\n got: %#v", k, k, w) + } + }) + } +} |