package cnp import "testing" var escapes = map[string]string{ "": ``, "ContNet": `ContNet`, " ": `\_`, "=": `\-`, "\n": `\n`, "\x00": `\0`, "\\": `\\`, "a\nb c=d\x00e\\f": `a\nb\_c\-d\0e\\f`, "\n\n\n": `\n\n\n`, "===": `\-\-\-`, " ": `\_\_\_`, "\x00\x00\x00": `\0\0\0`, "\\\\\\": `\\\\\\`, " =\n\x00\\": `\_\-\n\0\\`, "\b5Ὂg̀9! ℃ᾭG": "\b5Ὂg̀9!\\_℃ᾭG", "\xff\x00\xee\xaa\xee": "\xff\\0\xee\xaa\xee", "\x00\x10\x20\x30\x40": "\\0\x10\\_\x30\x40", "\x10\x50\x90\xe0": "\x10\x50\x90\xe0", "Hello, 世界": `Hello,\_世界`, "\xed\x9f\xbf": "\xed\x9f\xbf", "\xee\x80\x80": "\xee\x80\x80", "\xef\xbf\xbd": "\xef\xbf\xbd", "\x80\x80\x80\x80": "\x80\x80\x80\x80", } func TestEscape(t *testing.T) { for k, v := range escapes { e := string(Escape(k)) if e != v { t.Errorf("Escape(%q) -> %q, expected %q", k, e, v) } } for i := 0; i <= 255; i++ { switch i { case '\x00', ' ', '=', '\n', '\\': continue default: s := string([]byte{byte(i)}) b := Escape(s) if s != string(b) { t.Errorf("Escape(%q) -> %q, expected %q", s, b, s) } } } } func TestUnEscape(t *testing.T) { for k, v := range escapes { u, err := Unescape([]byte(v)) if err != nil { t.Errorf("Unescape(%q): error: %s", v, err) } else if u != k { t.Errorf("Unescape(%q) -> %q, expected %q", v, u, k) } } for i := 0; i <= 255; i++ { switch i { case '\x00', ' ', '=', '\n', '\\': continue default: b := []byte{byte(i)} s, err := Unescape(b) if err != nil { t.Errorf("Unescape(%q): error: %s", b, err) } else if string(b) != s { t.Errorf("Escape(%q) -> %q, expected %q", b, s, b) } } } } var headers = map[string]struct { h Header e error }{ // invalid version "cnp/0.4ok\n": {e: ErrorSyntax{}}, "cwp/0.4 ok\n": {e: ErrorSyntax{}}, "cnp/0.04 ok\n": {e: ErrorSyntax{}}, "cnp/00.4 ok\n": {e: ErrorSyntax{}}, "cnp/0..4 ok\n": {e: ErrorSyntax{}}, "cnp/.4 ok\n": {e: ErrorSyntax{}}, "cnp/0. ok\n": {e: ErrorSyntax{}}, "cnp/. ok\n": {e: ErrorSyntax{}}, "cnp/0,4 ok\n": {e: ErrorSyntax{}}, "/0.4 ok\n": {e: ErrorSyntax{}}, "0.4 ok\n": {e: ErrorSyntax{}}, "cnp/ ok\n": {e: ErrorSyntax{}}, "cnp ok\n": {e: ErrorSyntax{}}, "cnp.0.4 ok\n": {e: ErrorSyntax{}}, "cnp/04 ok\n": {e: ErrorSyntax{}}, "cnp/4 ok\n": {e: ErrorSyntax{}}, "cnp/0 ok\n": {e: ErrorSyntax{}}, "cnp/0 4 ok\n": {e: ErrorSyntax{}}, "cnp/0/4 ok\n": {e: ErrorSyntax{}}, // missing/invalid intent "cnp/0.4\n": {e: ErrorSyntax{}}, "cnp/0.4 \n": {e: ErrorSyntax{}}, "cnp/0.4 o\x00k\n": {e: ErrorSyntax{}}, "cnp/0.4 foo=bar\n": {e: ErrorSyntax{}}, // missing/invalid line end "cnp/0.4 ok \n": {e: ErrorSyntax{}}, "cnp/0.4 ok\n\n": {e: ErrorSyntax{}}, "cnp/0.4 ok": {e: ErrorSyntax{}}, "cnp/0.4 ok ": {e: ErrorSyntax{}}, "cnp/0.4 ok foo=bar \n": {e: ErrorSyntax{}}, "cnp/0.4 ok foo=bar": {e: ErrorSyntax{}}, "cnp/0.4 ok = =\n": {e: ErrorSyntax{}}, // spaces "cnp/0.4 ok foo=bar\n": {e: ErrorSyntax{}}, "cnp/0.4 ok\n": {e: ErrorSyntax{}}, "cnp/0.4\tok\n": {e: ErrorSyntax{}}, // invalid params "cnp/0.4 ok foo==bar\n": {e: ErrorSyntax{}}, "cnp/0.4 ok foo=bar=baz\n": {e: ErrorSyntax{}}, "cnp/0.4 ok foo=bar baz=quux \n": {e: ErrorSyntax{}}, "cnp/0.4 ok foo\\-bar\n": {e: ErrorSyntax{}}, // invalid escape sequences "cnp/0.4 o\\k\n": {e: ErrorSyntax{}}, "cnp/0.4 ok qwe=\\\n": {e: ErrorSyntax{}}, "cnp/0.4 ok fo\\o=bar\n": {e: ErrorSyntax{}}, // valid "cnp/0.0 ok\n": {h: Header{0, 0, "ok", nil}}, "cnp/0.4 ok\n": {h: Header{0, 4, "ok", nil}}, "cnp/1.0 ok\n": {h: Header{1, 0, "ok", nil}}, "cnp/123456.987654 ok\n": {h: Header{123456, 987654, "ok", nil}}, "cnp/0.1 ok\n": {h: Header{0, 1, "ok", nil}}, "cnp/0.4 ok\r\n": {h: Header{0, 4, "ok\r", nil}}, "cnp/0.4 foo\\nbar\n": {h: Header{0, 4, "foo\nbar", nil}}, "cnp/0.4 \\-\\_\\n\\0\\\\\n": {h: Header{0, 4, "= \n\x00\\", nil}}, // valid with params "cnp/0.4 ok type=text/plain\n": {h: Header{0, 4, "ok", Parameters{"type": "text/plain"}}}, "cnp/0.4 ok baz=quux foo=bar qwe=asd\n": {h: Header{0, 4, "ok", Parameters{"foo": "bar", "baz": "quux", "qwe": "asd"}}}, "cnp/0.4 ok = \\_=\\0 \\-=\\n\r\n": {h: Header{0, 4, "ok", Parameters{"": "", "=": "\n\r", " ": "\x00"}}}, } func TestHeaderParse(t *testing.T) { for raw, tst := range headers { hdr, err := ParseHeader([]byte(raw)) if err != nil || tst.e != nil { if !errorEqual(err, tst.e) { t.Errorf("ParseHeader(%q): expected error %+v, got %+v (%v)", raw, tst.e, err, err) } } else if !headerEqual(tst.h, hdr) { t.Errorf("ParseHeader(%q): expected %+v, got %+v", raw, tst.h, hdr) } } } func TestHeaderCompose(t *testing.T) { for raw, tst := range headers { if tst.e != nil { continue } // Parameters.Write currently sorts parameter keys /*if len(tst.h.Parameters) > 1 { continue // can't depend on parameter order }*/ str := tst.h.String() if raw != str { t.Errorf("%+v.String(): expected %q, got %q", tst.h, raw, str) } } } func TestNewHeader(t *testing.T) { raw := "cnp/0.4 ok baz=quux foo=bar qwe=asd\n" hdr := Header{0, 4, "ok", Parameters{"foo": "bar", "baz": "quux", "qwe": "asd"}} h := NewHeader("ok", Parameters{"foo": "bar", "baz": "quux", "qwe": "asd"}) if !headerEqual(hdr, h) { t.Errorf("%+v: expected %+v", h, hdr) } s := h.String() if raw != s { t.Errorf("%q: expected %q", h, hdr) } raw = "cnp/0.4 ok\n" hdr = Header{0, 4, "ok", nil} h = NewHeader("ok", nil) if !headerEqual(hdr, h) { t.Errorf("%+v: expected %+v", h, hdr) } s = h.String() if raw != s { t.Errorf("%q: expected %q", h, hdr) } }