ソースを参照

Add support for message tags from IRCv3 to IRCReader. Fixes #6

ReadLine now parses tags out of incoming lines (tags are not currently passed through the encoder)

IRCParser.tokeniseLine() now understands that tags may exist at the start of a line and tokenises accordingly.
(In reality, the only time it ever sees them is during testing)

Parser processLine now looks for timestamps from tags from the ReadLine, not by parsing token[0] itself.

Made IRCReader tests a lot less annoying to work with.
pull/10/head
Shane Mc Cormack 9年前
コミット
c545730074

+ 30
- 5
irc/src/com/dmdirc/parser/irc/IRCParser.java ファイルの表示

@@ -59,6 +59,8 @@ import java.security.KeyManagementException;
59 59
 import java.security.NoSuchAlgorithmException;
60 60
 import java.security.SecureRandom;
61 61
 import java.security.cert.X509Certificate;
62
+import java.text.SimpleDateFormat;
63
+import java.text.ParseException;
62 64
 import java.util.ArrayList;
63 65
 import java.util.Arrays;
64 66
 import java.util.Collection;
@@ -915,9 +917,28 @@ public class IRCParser extends BaseSocketAwareParser implements SecureParser, En
915 917
             return new String[]{""};
916 918
         }
917 919
 
918
-        final int lastarg = line.indexOf(" :");
920
+        int lastarg = line.indexOf(" :");
919 921
         String[] tokens;
920 922
 
923
+        // Check for IRC Tags.
924
+        if (line.charAt(0) == '@') {
925
+            // We have tags.
926
+            tokens = line.split(" ", 2);
927
+            final int tsEnd = tokens[0].indexOf('@', 1);
928
+            boolean hasTSIRCDate = false;
929
+            if (tsEnd > -1) {
930
+                try {
931
+                    final long ts = Long.parseLong(tokens[0].substring(1, tsEnd));
932
+                    hasTSIRCDate = true;
933
+                } catch (final NumberFormatException nfe) { /* Not a timestamp. */ }
934
+            }
935
+
936
+            if (!hasTSIRCDate) {
937
+                // IRCv3 Tags, last arg is actually the second " :"
938
+                lastarg = line.indexOf(" :", lastarg+1);
939
+            }
940
+        }
941
+
921 942
         if (lastarg > -1) {
922 943
             final String[] temp = line.substring(0, lastarg).split(" ");
923 944
             tokens = new String[temp.length + 1];
@@ -1076,13 +1097,17 @@ public class IRCParser extends BaseSocketAwareParser implements SecureParser, En
1076 1097
         callDataIn(line.getLine());
1077 1098
         final String[] token = line.getTokens();
1078 1099
         Date lineTS = new Date();
1079
-        if (!token[0].isEmpty() && token[0].charAt(0) == '@') {
1100
+
1101
+        if (line.getTags().containsKey("tsirc date")) {
1080 1102
             try {
1081
-                final int tsEnd = token[0].indexOf('@', 1);
1082
-                final long ts = Long.parseLong(token[0].substring(1, tsEnd));
1083
-                token[0] = token[0].substring(tsEnd + 1);
1103
+                final long ts = Long.parseLong(line.getTags().get("tsirc date"));
1084 1104
                 lineTS = new Date(ts - tsdiff);
1085 1105
             } catch (final NumberFormatException nfe) { /* Do nothing. */ }
1106
+        } else if (line.getTags().containsKey("time")) {
1107
+            final SimpleDateFormat servertime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
1108
+            try {
1109
+                lineTS = servertime.parse(line.getTags().get("time"));
1110
+            } catch (final ParseException pe) { /* Do nothing. */ }
1086 1111
         }
1087 1112
 
1088 1113
         setPingNeeded(false);

+ 77
- 5
irc/src/com/dmdirc/parser/irc/IRCReader.java ファイルの表示

@@ -32,6 +32,12 @@ import java.nio.charset.CharacterCodingException;
32 32
 import java.nio.charset.Charset;
33 33
 import java.nio.charset.CharsetDecoder;
34 34
 import java.nio.charset.CodingErrorAction;
35
+import java.text.SimpleDateFormat;
36
+import java.util.Arrays;
37
+import java.util.Collections;
38
+import java.util.Date;
39
+import java.util.HashMap;
40
+import java.util.Map;
35 41
 
36 42
 /**
37 43
  * A {@link java.io.BufferedReader}-style reader that is aware of the IRC
@@ -42,7 +48,7 @@ import java.nio.charset.CodingErrorAction;
42 48
 public class IRCReader implements Closeable {
43 49
 
44 50
     /** Maximum length for an IRC line in bytes. */
45
-    private static final int LINE_LENGTH = 512;
51
+    private static final int LINE_LENGTH = 1024;
46 52
     /** The input stream to read input from. */
47 53
     private final InputStream stream;
48 54
     /** The encoder to use to encode lines. */
@@ -93,7 +99,12 @@ public class IRCReader implements Closeable {
93 99
         int paramOffset = -1;
94 100
         int chr = 0, lastChr = 0;
95 101
 
96
-        while (offset < 512 && (chr = stream.read()) > -1) {
102
+        boolean hasTags = false;
103
+        boolean endOfTags = false;
104
+        boolean hasV3Tags = false;
105
+        boolean foundFirstSpace = false;
106
+
107
+        while (offset < LINE_LENGTH && (chr = stream.read()) > -1) {
97 108
             if (chr == '\r') {
98 109
                 continue;
99 110
             } else if (chr == '\n') {
@@ -101,11 +112,32 @@ public class IRCReader implements Closeable {
101 112
                 break;
102 113
             }
103 114
 
115
+            if (hasTags && !endOfTags) {
116
+                // Tags end either at the first @ for non-v3 tags or space for v3
117
+                if (offset > 0 && ((chr == '@' && !hasV3Tags) || chr == ' ')) {
118
+                    endOfTags = true;
119
+                    hasV3Tags = (chr == ' ');
120
+                }
121
+                // If we are still possibly looking at tags, and we find a non-numeric
122
+                // character, then we probably have v3Tags
123
+                if (!endOfTags && (chr < '0' || chr > '9')) {
124
+                    hasV3Tags = true;
125
+                }
126
+            } else if (offset == 0 && chr == '@') {
127
+                hasTags = true;
128
+            } else if (offset == 0) {
129
+                endOfTags = true;
130
+            }
131
+
104 132
             line[offset++] = (byte) chr;
105 133
 
106 134
             if (lastChr == ' ' && chr == ':' && paramOffset == -1) {
107 135
                 // We've found the last param
108
-                paramOffset = offset;
136
+                if (!hasV3Tags || foundFirstSpace) {
137
+                    paramOffset = offset;
138
+                } else if (hasV3Tags) {
139
+                    foundFirstSpace = true;
140
+                }
109 141
             }
110 142
 
111 143
             lastChr = chr;
@@ -209,16 +241,47 @@ public class IRCReader implements Closeable {
209 241
         private final String line;
210 242
         /** The tokens found in the line, individually encoded as appropriate. */
211 243
         private final String[] tokens;
244
+        /** The tags (if any) found in the line, individually encoded as appropriate. */
245
+        private final Map<String,String> tags = new HashMap<>();
212 246
 
213 247
         /**
214 248
          * Creates a new instance of {@link ReadLine} with the specified line
215 249
          * and tokens.
216 250
          *
217 251
          * @param line A string representation of the line
218
-         * @param tokens The tokens which make up the line
252
+         * @param lineTokens The tokens which make up the line
219 253
          */
220
-        public ReadLine(final String line, final String[] tokens) {
254
+        public ReadLine(final String line, final String[] lineTokens) {
221 255
             this.line = line;
256
+
257
+            String[] tokens = lineTokens;
258
+            if (!tokens[0].isEmpty() && tokens[0].charAt(0) == '@') {
259
+                // Look for old-style TSIRC timestamp first.
260
+                final int tsEnd = tokens[0].indexOf('@', 1);
261
+                boolean hasTSIRCDate = false;
262
+                if (tsEnd > -1) {
263
+                    try {
264
+                        final long ts = Long.parseLong(tokens[0].substring(1, tsEnd));
265
+                        tags.put("tsirc date", tokens[0].substring(1, tsEnd));
266
+                        hasTSIRCDate = true;
267
+                        tokens[0] = tokens[0].substring(tsEnd + 1);
268
+                    } catch (final NumberFormatException nfe) { /* Not a timestamp. */ }
269
+                }
270
+
271
+                if (!hasTSIRCDate) {
272
+                    final String[] lineTags = tokens[0].substring(1).split(";");
273
+                    for (final String keyVal : lineTags) {
274
+                        if (!keyVal.isEmpty()) {
275
+                            final String[] keyValue = keyVal.split("=", 2);
276
+                            tags.put(keyValue[0], keyValue.length > 1 ? keyValue[1] : "");
277
+                        }
278
+                    }
279
+
280
+                    tokens = new String[lineTokens.length - 1];
281
+                    System.arraycopy(lineTokens, 1, tokens, 0, lineTokens.length - 1);
282
+                }
283
+            }
284
+
222 285
             this.tokens = tokens;
223 286
         }
224 287
 
@@ -243,5 +306,14 @@ public class IRCReader implements Closeable {
243 306
         public String[] getTokens() {
244 307
             return tokens;
245 308
         }
309
+
310
+        /**
311
+         * Retrieves a map of tags extracted from the specified line.
312
+         *
313
+         * @return The line's tags
314
+         */
315
+        public Map<String,String> getTags() {
316
+            return tags;
317
+        }
246 318
     }
247 319
 }

+ 99
- 62
irc/test/com/dmdirc/parser/irc/IRCReaderTest.java ファイルの表示

@@ -25,9 +25,13 @@ package com.dmdirc.parser.irc;
25 25
 import com.dmdirc.parser.interfaces.Encoder;
26 26
 import com.dmdirc.parser.irc.IRCReader.ReadLine;
27 27
 
28
+import java.io.ByteArrayInputStream;
28 29
 import java.io.IOException;
29 30
 import java.io.InputStream;
30 31
 import java.nio.charset.Charset;
32
+import java.text.SimpleDateFormat;
33
+import java.util.Arrays;
34
+import java.util.Date;
31 35
 
32 36
 import org.junit.Assert;
33 37
 import org.junit.Test;
@@ -40,12 +44,9 @@ public class IRCReaderTest {
40 44
     /** Reads and verifies a single line. */
41 45
     @Test
42 46
     public void testReadLine() throws IOException {
43
-        final InputStream stream = mock(InputStream.class);
47
+        final InputStream stream = new ByteArrayInputStream("test\r\n".getBytes());
44 48
         final Encoder encoder = mock(Encoder.class);
45 49
 
46
-        when(stream.read()).thenReturn((int) 't', (int) 'e', (int) 's',
47
-                (int) 't', (int) '\r', (int) '\n');
48
-
49 50
         final IRCReader reader = new IRCReader(stream, encoder);
50 51
         final ReadLine line = reader.readLine();
51 52
 
@@ -55,12 +56,9 @@ public class IRCReaderTest {
55 56
     /** Reads and verifies a single line with only a trailing LF. */
56 57
     @Test
57 58
     public void testReadLineWithOnlyLF() throws IOException {
58
-        final InputStream stream = mock(InputStream.class);
59
+        final InputStream stream = new ByteArrayInputStream("test\n".getBytes());
59 60
         final Encoder encoder = mock(Encoder.class);
60 61
 
61
-        when(stream.read()).thenReturn((int) 't', (int) 'e', (int) 's',
62
-                (int) 't', (int) '\n');
63
-
64 62
         final IRCReader reader = new IRCReader(stream, encoder);
65 63
         final ReadLine line = reader.readLine();
66 64
 
@@ -70,12 +68,9 @@ public class IRCReaderTest {
70 68
     /** Reads and verifies a single line with a trailing parameter. */
71 69
     @Test
72 70
     public void testReadLineWithParameter() throws IOException {
73
-        final InputStream stream = mock(InputStream.class);
71
+        final InputStream stream = new ByteArrayInputStream("te t :foo\r\n".getBytes());
74 72
         final Encoder encoder = mock(Encoder.class);
75 73
 
76
-        when(stream.read()).thenReturn((int) 't', (int) 'e', (int) ' ',
77
-                (int) 't', (int) ' ', (int) ':', (int) 'f', (int) 'o',
78
-                (int) 'o', (int) '\r', (int) '\n');
79 74
         when(encoder.encode((String) isNull(), (String) isNull(),
80 75
                 (byte[]) anyObject(), anyInt(), eq(3)))
81 76
                 .thenReturn("encoded");
@@ -90,15 +85,9 @@ public class IRCReaderTest {
90 85
     /** Reads and verifies a single line with a trailing parameter. */
91 86
     @Test
92 87
     public void testReadLineWithMultipleSpaces() throws IOException {
93
-        final InputStream stream = mock(InputStream.class);
88
+        final InputStream stream = new ByteArrayInputStream("foo bar  baz  :qux  baz\r\n".getBytes());
94 89
         final Encoder encoder = mock(Encoder.class);
95 90
 
96
-        when(stream.read()).thenReturn((int) 'f', (int) 'o', (int) 'o',
97
-                (int) ' ', (int) 'b', (int) 'a', (int) 'r',
98
-                (int) ' ', (int) ' ', (int) 'b', (int) 'a', (int) 'z',
99
-                (int) ' ', (int) ' ', (int) ':', (int) 'q', (int) 'u',
100
-                (int) 'x', (int) ' ', (int) ' ', (int) 'b', (int) 'a', (int) 'z',
101
-                (int) '\r', (int) '\n');
102 91
         when(encoder.encode((String) isNull(), (String) isNull(),
103 92
                 (byte[]) anyObject(), eq(15), eq(8)))
104 93
                 .thenReturn("qux  baz");
@@ -106,20 +95,15 @@ public class IRCReaderTest {
106 95
         final IRCReader reader = new IRCReader(stream, encoder);
107 96
         final ReadLine line = reader.readLine();
108 97
 
109
-        assertArrayEquals(new String[]{"foo", "bar", "baz", "qux  baz",},
110
-                line.getTokens());
98
+        assertArrayEquals(new String[]{"foo", "bar", "baz", "qux  baz",}, line.getTokens());
111 99
     }
112 100
 
113 101
     /** Verifies that a source is extracted properly. */
114 102
     @Test
115 103
     public void testGetSource() throws IOException {
116
-        final InputStream stream = mock(InputStream.class);
104
+        final InputStream stream = new ByteArrayInputStream(":src x :o\r\n".getBytes());
117 105
         final Encoder encoder = mock(Encoder.class);
118 106
 
119
-        when(stream.read()).thenReturn((int) ':', (int) 's', (int) 'r',
120
-                (int) 'c', (int) ' ', (int) 'x', (int) ' ', (int) ':',
121
-                (int) 'o', (int) '\r', (int) '\n');
122
-
123 107
         new IRCReader(stream, encoder).readLine();
124 108
 
125 109
         verify(encoder).encode(eq("src"), anyString(),
@@ -129,13 +113,9 @@ public class IRCReaderTest {
129 113
     /** Verifies that no source is passed if the source is empty. */
130 114
     @Test
131 115
     public void testGetEmptySource() throws IOException {
132
-        final InputStream stream = mock(InputStream.class);
116
+        final InputStream stream = new ByteArrayInputStream(": rc x :o\r\n".getBytes());
133 117
         final Encoder encoder = mock(Encoder.class);
134 118
 
135
-        when(stream.read()).thenReturn((int) ':', (int) ' ', (int) 'r',
136
-                (int) 'c', (int) ' ', (int) 'x', (int) ' ', (int) ':',
137
-                (int) 'o', (int) '\r', (int) '\n');
138
-
139 119
         new IRCReader(stream, encoder).readLine();
140 120
 
141 121
         verify(encoder).encode((String) isNull(), anyString(),
@@ -145,13 +125,9 @@ public class IRCReaderTest {
145 125
     /** Verifies that a destination is extracted properly. */
146 126
     @Test
147 127
     public void testGetDestination() throws IOException {
148
-        final InputStream stream = mock(InputStream.class);
128
+        final InputStream stream = new ByteArrayInputStream(":src x y :z\r\n".getBytes());
149 129
         final Encoder encoder = mock(Encoder.class);
150 130
 
151
-        when(stream.read()).thenReturn((int) ':', (int) 's', (int) 'r',
152
-                (int) 'c', (int) ' ', (int) 'x', (int) ' ', (int) 'y',
153
-                (int) ' ', (int) ':', (int) 'z', (int) '\r', (int) '\n');
154
-
155 131
         new IRCReader(stream, encoder).readLine();
156 132
 
157 133
         verify(encoder).encode(anyString(), eq("y"), (byte[]) anyObject(),
@@ -161,13 +137,9 @@ public class IRCReaderTest {
161 137
     /** Verifies that no destination is extracted if there's no source. */
162 138
     @Test
163 139
     public void testGetDestinationNoSource() throws IOException {
164
-        final InputStream stream = mock(InputStream.class);
140
+        final InputStream stream = new ByteArrayInputStream("_src x y :z\r\n".getBytes());
165 141
         final Encoder encoder = mock(Encoder.class);
166 142
 
167
-        when(stream.read()).thenReturn((int) '_', (int) 's', (int) 'r',
168
-                (int) 'c', (int) ' ', (int) 'x', (int) ' ', (int) 'y',
169
-                (int) ' ', (int) ':', (int) 'z', (int) '\r', (int) '\n');
170
-
171 143
         new IRCReader(stream, encoder).readLine();
172 144
 
173 145
         verify(encoder).encode(anyString(), (String) isNull(),
@@ -177,13 +149,9 @@ public class IRCReaderTest {
177 149
     /** Verifies that no destination is extracted if there are too few args. */
178 150
     @Test
179 151
     public void testGetDestinationTooShort() throws IOException {
180
-        final InputStream stream = mock(InputStream.class);
152
+        final InputStream stream = new ByteArrayInputStream(":src x :abz\r\n".getBytes());
181 153
         final Encoder encoder = mock(Encoder.class);
182 154
 
183
-        when(stream.read()).thenReturn((int) ':', (int) 's', (int) 'r',
184
-                (int) 'c', (int) ' ', (int) 'x', (int) ' ', (int) ':',
185
-                (int) 'a', (int) 'b', (int) 'z', (int) '\r', (int) '\n');
186
-
187 155
         new IRCReader(stream, encoder).readLine();
188 156
 
189 157
         verify(encoder).encode(anyString(), (String) isNull(),
@@ -193,18 +161,12 @@ public class IRCReaderTest {
193 161
     /** Verifies that a numeric's destination is extracted properly. */
194 162
     @Test
195 163
     public void testGetDestinationWithNumeric() throws IOException {
196
-        final InputStream stream = mock(InputStream.class);
164
+        final InputStream stream = new ByteArrayInputStream(":src 1 x y z :x\r\n".getBytes());
197 165
         final Encoder encoder = mock(Encoder.class);
198 166
 
199
-        when(stream.read()).thenReturn((int) ':', (int) 's', (int) 'r',
200
-                (int) 'c', (int) ' ', (int) '1', (int) ' ', (int) 'x',
201
-                (int) ' ', (int) 'y', (int) ' ', (int) 'z', (int) ' ',
202
-                (int) ':', (int) 'x', (int) '\r', (int) '\n');
203
-
204 167
         new IRCReader(stream, encoder).readLine();
205 168
 
206
-        verify(encoder).encode(anyString(), eq("y"),
207
-                (byte[]) anyObject(), anyInt(), anyInt());
169
+        verify(encoder).encode(anyString(), eq("y"), (byte[]) anyObject(), anyInt(), anyInt());
208 170
     }
209 171
 
210 172
     /** Verifies that the close call is proxied to the stream. */
@@ -224,20 +186,95 @@ public class IRCReaderTest {
224 186
         final InputStream stream = mock(InputStream.class);
225 187
         final Encoder encoder = mock(Encoder.class);
226 188
 
227
-        when(stream.read()).thenReturn((int) ':', (int) 's', (int) 'r',
228
-                (int) 'c', (int) ' ', (int) '1', (int) ' ', 0xF6,
229
-                (int) ' ', (int) 'y', (int) ' ', (int) 'z', (int) ' ',
189
+        when(stream.read()).thenReturn((int) ':', (int) 's', (int) 'r', (int) 'c', (int) ' ',
190
+                (int) '1', (int) ' ', 0xF6, (int) ' ', (int) 'y', (int) ' ', (int) 'z', (int) ' ',
230 191
                 (int) ':', (int) 'x', (int) '\r', (int) '\n');
231 192
 
232 193
         when(encoder.encode(anyString(), anyString(),
233 194
                 (byte[]) any(), anyInt(), anyInt())).thenReturn("x");
234 195
 
235
-        final ReadLine line = new IRCReader(stream, encoder,
236
-                Charset.forName("UTF-8")).readLine();
196
+        final ReadLine line = new IRCReader(stream, encoder, Charset.forName("UTF-8")).readLine();
197
+
198
+        Assert.assertArrayEquals(new String[]{":src", "1", "\uFFFD", "y", "z", "x"}, line.getTokens());
199
+    }
200
+
201
+    /** Verify tokeniser with TSIRC Time Stamp */
202
+    @Test
203
+    public void testReadLineTSIRC() throws IOException {
204
+        final ReadLine line = new ReadLine("", IRCParser.tokeniseLine("@123@:test ing"));
237 205
 
238
-        Assert.assertArrayEquals(new String[] {
239
-            ":src", "1", "\uFFFD", "y", "z", "x"
240
-        }, line.getTokens());
206
+        assertEquals(":test", line.getTokens()[0]);
207
+        assertEquals("ing", line.getTokens()[1]);
208
+        assertEquals("123", line.getTags().get("tsirc date"));
209
+        assertNull(line.getTags().get("time"));
241 210
     }
242 211
 
212
+    /** Verify tokeniser with IRCv3 tags */
213
+    @Test
214
+    public void testReadLineIRCv3TS() throws IOException {
215
+        final SimpleDateFormat servertime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
216
+        final ReadLine line = new ReadLine("", IRCParser.tokeniseLine("@time="+servertime.format(new Date(123))+";something=else;foobar; :test ing"));
217
+
218
+        assertEquals(":test", line.getTokens()[0]);
219
+        assertEquals("ing", line.getTokens()[1]);
220
+        assertNull(line.getTags().get("tsirc date"));
221
+        assertEquals(servertime.format(new Date(123)), line.getTags().get("time"));
222
+    }
223
+
224
+
225
+    /** Verify tokeniser with a numeric tag timestamp */
226
+    @Test
227
+    public void testReadLineNumericTag() throws IOException {
228
+        final ReadLine line = new ReadLine("", IRCParser.tokeniseLine("@123 :test ing"));
229
+
230
+        assertEquals(":test", line.getTokens()[0]);
231
+        assertEquals("ing", line.getTokens()[1]);
232
+        assertTrue(line.getTags().containsKey("123"));
233
+    }
234
+
235
+
236
+    /** Verify line with TSIRC Time Stamp */
237
+    @Test
238
+    public void testReaderTSIRC() throws IOException {
239
+        final InputStream stream = new ByteArrayInputStream("@123@:test ing\r\n".getBytes());
240
+        final Encoder encoder = mock(Encoder.class);
241
+
242
+        final IRCReader reader = new IRCReader(stream, encoder);
243
+        final ReadLine line = reader.readLine();
244
+
245
+        assertEquals(":test", line.getTokens()[0]);
246
+        assertEquals("ing", line.getTokens()[1]);
247
+        assertEquals("123", line.getTags().get("tsirc date"));
248
+        assertNull(line.getTags().get("time"));
249
+    }
250
+
251
+    /** Verify line with IRCv3 timestamp */
252
+    @Test
253
+    public void testReaderIRCv3TS() throws IOException {
254
+        final SimpleDateFormat servertime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
255
+        final InputStream stream = new ByteArrayInputStream(("@time="+servertime.format(new Date(123))+";something=else;foobar; :test ing\r\n").getBytes());
256
+        final Encoder encoder = mock(Encoder.class);
257
+
258
+        final IRCReader reader = new IRCReader(stream, encoder);
259
+        final ReadLine line = reader.readLine();
260
+
261
+        assertEquals(":test", line.getTokens()[0]);
262
+        assertEquals("ing", line.getTokens()[1]);
263
+        assertNull(line.getTags().get("tsirc date"));
264
+        assertEquals(servertime.format(new Date(123)), line.getTags().get("time"));
265
+    }
266
+
267
+    /** Verify line with a numeric tag timestamp */
268
+    @Test
269
+    public void testReaderNumericTag() throws IOException {
270
+        final InputStream stream = new ByteArrayInputStream("@123 :test ing\r\n".getBytes());
271
+        final Encoder encoder = mock(Encoder.class);
272
+
273
+        final IRCReader reader = new IRCReader(stream, encoder);
274
+        final ReadLine line = reader.readLine();
275
+
276
+        assertEquals(":test", line.getTokens()[0]);
277
+        assertEquals("ing", line.getTokens()[1]);
278
+        assertTrue(line.getTags().containsKey("123"));
279
+    }
243 280
 }

読み込み中…
キャンセル
保存