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{Emphasized: true}, "foo"}, }}, "__foo": Text{[]Span{ Span{Format{Alternate: true}, "foo"}, }}, "``foo": Text{[]Span{ Span{Format{Code: true}, "foo"}, }}, "\"\"foo": Text{[]Span{ Span{Format{Quote: 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{Emphasized: true}, "*"}, }}, "foo****": Text{[]Span{ Span{Format{}, "foo"}, }}, "*foo": Text{[]Span{ Span{Format{}, "*foo"}, }}, "****foo": Text{[]Span{ Span{Format{}, "foo"}, }}, "******foo": Text{[]Span{ Span{Format{Emphasized: true}, "foo"}, }}, "foo ** bar": Text{[]Span{ Span{Format{}, "foo "}, Span{Format{Emphasized: true}, " bar"}, }}, "foo** bar": Text{[]Span{ Span{Format{}, "foo"}, Span{Format{Emphasized: true}, " bar"}, }}, "foo **bar": Text{[]Span{ Span{Format{}, "foo "}, Span{Format{Emphasized: true}, "bar"}, }}, "foo ** bar ** baz": Text{[]Span{ Span{Format{}, "foo "}, Span{Format{Emphasized: true}, " bar "}, Span{Format{}, " baz"}, }}, "foo ** bar** baz": Text{[]Span{ Span{Format{}, "foo "}, Span{Format{Emphasized: true}, " bar"}, Span{Format{}, " baz"}, }}, "**\"\"**foo": Text{[]Span{ Span{Format{Quote: true}, "foo"}, }}, "***": Text{[]Span{ Span{Format{Emphasized: 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{Emphasized: true}, " "}, Span{Format{Emphasized: true, Alternate: true}, " "}, }}, "**": Text{[]Span{}}, "**``\"\"__foo": Text{[]Span{ Span{Format{Emphasized: true, Code: true, Quote: true, Alternate: true}, "foo"}, }}, "**foo__bar**baz": Text{[]Span{ Span{Format{Emphasized: true}, "foo"}, Span{Format{Emphasized: true, Alternate: true}, "bar"}, Span{Format{Alternate: 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{Emphasized: true, Link: "http://example.com"}, "bar "}, Span{Format{Emphasized: true}, "baz"}, }}, "__@@http://example.com/__/ foo __bar @@": Text{[]Span{ Span{Format{Alternate: true, Link: "http://example.com/__/"}, "foo "}, Span{Format{Link: "http://example.com/__/"}, "bar "}, }}, "\"\"\\ asd \\ zxc\\ ": Text{[]Span{ Span{Format{Quote: true, Code: 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{Alternate: true}, "test_"}, }}, "_**test": Text{[]Span{ Span{Format{}, "_"}, Span{Format{Emphasized: 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", "@@!!##\"\"//\"\"__``**%%^^&&++==\x01\x01\\": "\\@\\@!!##\\\"\\\"//\\\"\\\"\\_\\_\\`\\`\\*\\*%%^^&&++==\x01\x01\\\\", `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):\nexpected: %q\n 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{Emphasized: 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{Emphasized: true}, "bar**baz**quux"}, Span{Format{}, "qweasd"}, }}}}, "**foo\n\nbar": TextFmtContents{[]Text{ Text{[]Span{Span{Format{Emphasized: true}, "foo"}}}, Text{[]Span{Span{Format{}, "bar"}}}, }}, } 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{Emphasized: true}, "foo"}, }}, }}, "foo **bar baz\n\nquux\n": TextFmtContents{[]Text{ Text{[]Span{ Span{Format{}, "foo "}, Span{Format{Emphasized: 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{Emphasized: true}, "bar"}, Span{Format{Emphasized: true, Code: true}, "baz"}, Span{Format{Code: true}, "quux"}, }}, Text{[]Span{ Span{Format{}, " "}, Span{Format{Quote: true}, "qwe "}, Span{Format{Alternate: true}, " asd "}, Span{Format{Code: true}, "zxc"}, Span{Format{Emphasized: true}, " "}, }}, Text{[]Span{ Span{Format{Alternate: true, Link: "http://example.com/__/"}, "exa"}, Span{Format{Link: "http://example.com/__/"}, "mple"}, Span{Format{}, " "}, Span{Format{Link: "href"}, "text"}, Span{Format{Alternate: true}, " test"}, }}, }}, "foo**bar\\*\\*baz\\*\\*quux**qweasd\n": TextFmtContents{[]Text{Text{[]Span{ Span{Format{}, "foo"}, Span{Format{Emphasized: true}, "bar**baz**quux"}, Span{Format{}, "qweasd"}, }}}}, "**1** **2** **3** **4** **5** **6** **7** **8**" + " **9** **10** **11** **12\n": TextFmtContents{[]Text{Text{[]Span{ Span{Format{Emphasized: true}, "1"}, Span{Format{}, " "}, Span{Format{Emphasized: true}, "2"}, Span{Format{}, " "}, Span{Format{Emphasized: true}, "3"}, Span{Format{}, " "}, Span{Format{Emphasized: true}, "4"}, Span{Format{}, " "}, Span{Format{Emphasized: true}, "5"}, Span{Format{}, " "}, Span{Format{Emphasized: true}, "6"}, Span{Format{}, " "}, Span{Format{Emphasized: true}, "7"}, Span{Format{}, " "}, Span{Format{Emphasized: true}, "8"}, Span{Format{}, " "}, Span{Format{Emphasized: true}, "9"}, Span{Format{}, " "}, Span{Format{Emphasized: true}, "10"}, Span{Format{}, " "}, Span{Format{Emphasized: true}, "11"}, Span{Format{}, " "}, Span{Format{Emphasized: true}, "12"}, }}}}, } 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() 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) } }) } }