github.com/la5nta/wl2k-go@v0.11.8/fbb/message_test.go (about) 1 // Copyright 2016 Martin Hebnes Pedersen (LA5NTA). All rights reserved. 2 // Use of this source code is governed by the MIT-license that can be 3 // found in the LICENSE file. 4 5 package fbb 6 7 import ( 8 "bytes" 9 "reflect" 10 "strings" 11 "testing" 12 "time" 13 "unicode" 14 ) 15 16 func TestReadMessageWithWhitespaceBeforeHeader(t *testing.T) { 17 m1 := NewMessage(Private, "one-long-mid") 18 m1.AddTo("N0CALL") 19 m1.SetFrom("LA5NTA") 20 m1.SetBody("Hello world") 21 22 // Write the message with leading whitespace garbage 23 var buf bytes.Buffer 24 buf.WriteString("\r\n\r\n\t ") 25 if err := m1.Write(&buf); err != nil { 26 t.Fatal(err) 27 } 28 29 // Read the message and verify that we decoded the header successfully. 30 m2 := &Message{} 31 if err := m2.ReadFrom(bytes.NewReader(buf.Bytes())); err != nil { 32 t.Fatal(err) 33 } 34 if !reflect.DeepEqual(m1.Header, m2.Header) { 35 t.Error("parsed message header differs", m1, m2) 36 } 37 } 38 39 func TestEmptyMessageReadError(t *testing.T) { 40 if err := (&Message{}).ReadFrom(strings.NewReader("")); err == nil { 41 t.Errorf("Reading empty message did not error") 42 } 43 if err := (&Message{}).ReadFrom(strings.NewReader("\r\n\r\nfoobar")); err == nil { 44 t.Errorf("Reading headerless message did not error") 45 } 46 } 47 48 func TestParseDate(t *testing.T) { 49 tests := []string{ 50 "2016/12/30 01:00", // The correct format according to winlink.org/b2f. 51 "2016.12.30 01:00", // RMS Relay store-and-forward re-formats date headers in this undocumented layout. 52 "2016-12-30 01:00", // Seen in a Radio Only message via RMS Relay-3.0.30.0. 53 "20161230010000", // Format known to be produced by some versions of BPQ Mail. 54 55 // Extended format support to ensure we support common email formats. 56 "Fri, 30 Dec 2016 01:00:00 -0000", // RFC 5322, Appendix A.1.1. 57 "Fri, 30 Dec 2016 01:00:00 GMT", // RFC 5322, Appendix A.6.2. Obsolete date. 58 } 59 expect := time.Date(2016, time.December, 30, 01, 00, 00, 00, time.UTC).Local() 60 61 for _, str := range tests { 62 got, _ := ParseDate(str) 63 if !got.Equal(expect) { 64 t.Errorf("Unexpected Time when parsing `%s`: %s", str, got) 65 } 66 } 67 } 68 69 func TestAddressFromString(t *testing.T) { 70 tests := map[string]Address{ 71 "LA5NTA": {Proto: "", Addr: "LA5NTA"}, 72 "la5nta": {Proto: "", Addr: "LA5NTA"}, 73 "LA5NTA@winlink.org": {Proto: "", Addr: "LA5NTA"}, 74 "LA5NTA@WINLINK.org": {Proto: "", Addr: "LA5NTA"}, 75 "la5nta@WINLINK.org": {Proto: "", Addr: "LA5NTA"}, 76 77 "foo@bar.baz": {Proto: "SMTP", Addr: "foo@bar.baz"}, 78 } 79 80 for str, expect := range tests { 81 got := AddressFromString(str) 82 if !reflect.DeepEqual(expect, got) { 83 t.Errorf("'%s' got %#v expected %#v", str, got, expect) 84 } 85 } 86 } 87 88 func TestEncodeNonASCIIFileNames(t *testing.T) { 89 msg := NewMessage(Private, "NOCALL") 90 msg.AddFile(NewFile("æøå.txt", []byte{})) 91 92 if h := msg.Header.Get("File"); IsIllegalHeader(h) { 93 t.Error("Non-ascii character in encoded File header") 94 } 95 } 96 97 func TestDecodeNonASCIIFileNames(t *testing.T) { 98 msg := NewMessage(Private, "NOCALL") 99 msg.AddFile(NewFile("æøå.txt", []byte{})) 100 101 samples := []string{ 102 msg.Header["File"][0], // Word encoded (round trip) 103 "0 æøå.txt", // UTF8 104 "0 \xE6\xF8\xE5.txt", // Latin1 105 } 106 107 for i, v := range samples { 108 msg.Header["File"][0] = v 109 110 var buf bytes.Buffer 111 msg.Write(&buf) 112 113 decoded := new(Message) 114 decoded.ReadFrom(&buf) 115 if msg.Files()[0].Name() != "æøå.txt" { 116 t.Errorf("Sample %d failed", i) 117 } 118 } 119 } 120 121 func TestEmptyAttachment(t *testing.T) { 122 msg := NewMessage(Private, "N0CALL") 123 msg.AddFile(NewFile("foo.txt", nil)) 124 var buf bytes.Buffer 125 if err := msg.Write(&buf); err != nil { 126 t.Fatalf("Error writing message: %v", err) 127 } 128 if !strings.Contains(buf.String(), "File: 0 foo.txt") { 129 t.Error("Expected File header") 130 } 131 decoded := new(Message) 132 if err := decoded.ReadFrom(&buf); err != nil { 133 t.Fatalf("Error while decoding produced message: %v", err) 134 } 135 if n := len(msg.Files()); n != 1 { 136 t.Fatalf("Expected one attachment after roundtrip, found %d", n) 137 } 138 f := msg.Files()[0] 139 if f.Size() != 0 { 140 t.Errorf("Expected size 0 after roundtrip, found %d", f.Size()) 141 } 142 if f.Name() != "foo.txt" { 143 t.Errorf("Got unexpected attachment name after roundtrip: %s", f.Name()) 144 } 145 body, err := msg.Body() 146 if err != nil { 147 t.Errorf("Got error reading body: %v", err) 148 } 149 if len(body) != 0 { 150 t.Errorf("Expected no body, got length %d", len(body)) 151 } 152 } 153 154 func IsIllegalHeader(str string) bool { 155 for _, c := range str { 156 if !IsGraphicASCII(c) { 157 return true 158 } 159 } 160 return false 161 } 162 163 func IsGraphicASCII(c rune) bool { 164 return c <= unicode.MaxASCII && unicode.IsGraphic(c) 165 }