OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "core/page/EventSourceParser.h" | |
6 | |
7 #include "core/page/EventSource.h" | |
8 #include "testing/gtest/include/gtest/gtest.h" | |
9 #include "wtf/text/CharacterNames.h" | |
10 | |
11 #include <string.h> | |
12 | |
13 namespace blink { | |
14 | |
15 namespace { | |
16 | |
17 struct EventOrReconnectionTimeSetting { | |
18 enum Type { | |
19 Event, | |
20 ReconnectionTimeSetting, | |
21 }; | |
22 | |
23 EventOrReconnectionTimeSetting(const AtomicString& event, const String& data , const AtomicString& id) | |
24 : type(Event) | |
25 , event(event) | |
26 , data(data) | |
27 , id(id) | |
28 , reconnectionTime(0) | |
29 { | |
30 } | |
31 explicit EventOrReconnectionTimeSetting(unsigned long long reconnectionTime) | |
32 : type(ReconnectionTimeSetting) | |
33 , reconnectionTime(reconnectionTime) | |
34 { | |
35 } | |
36 | |
37 const Type type; | |
38 const AtomicString event; | |
39 const String data; | |
40 const AtomicString id; | |
41 const unsigned long long reconnectionTime; | |
42 }; | |
43 | |
44 class Client : public GarbageCollectedFinalized<Client>, public EventSourceParse r::Client { | |
45 USING_GARBAGE_COLLECTED_MIXIN(Client); | |
46 public: | |
47 ~Client() override {} | |
48 const Vector<EventOrReconnectionTimeSetting>& events() const { return m_even ts; } | |
49 void onMessageEvent(const AtomicString& event, const String& data, const Ato micString& id) override | |
50 { | |
51 m_events.append(EventOrReconnectionTimeSetting(event, data, id)); | |
52 } | |
53 void onReconnectionTimeSet(unsigned long long reconnectionTime) override | |
54 { | |
55 m_events.append(EventOrReconnectionTimeSetting(reconnectionTime)); | |
56 } | |
57 | |
58 private: | |
59 Vector<EventOrReconnectionTimeSetting> m_events; | |
60 }; | |
61 | |
62 class StoppingClient : public GarbageCollectedFinalized<Client>, public EventSou rceParser::Client { | |
63 USING_GARBAGE_COLLECTED_MIXIN(StoppingClient); | |
64 public: | |
65 ~StoppingClient() override {} | |
66 const Vector<EventOrReconnectionTimeSetting>& events() const { return m_even ts; } | |
67 void setParser(EventSourceParser* parser) { m_parser = parser; } | |
68 void onMessageEvent(const AtomicString& event, const String& data, const Ato micString& id) override | |
69 { | |
70 m_parser->stop(); | |
71 m_events.append(EventOrReconnectionTimeSetting(event, data, id)); | |
72 } | |
73 void onReconnectionTimeSet(unsigned long long reconnectionTime) override | |
74 { | |
75 m_events.append(EventOrReconnectionTimeSetting(reconnectionTime)); | |
76 } | |
77 | |
78 DEFINE_INLINE_VIRTUAL_TRACE() | |
79 { | |
80 visitor->trace(m_parser); | |
81 EventSourceParser::Client::trace(visitor); | |
82 } | |
83 | |
84 private: | |
85 Member<EventSourceParser> m_parser; | |
86 Vector<EventOrReconnectionTimeSetting> m_events; | |
87 }; | |
88 | |
89 class EventSourceParserTest : public ::testing::Test { | |
90 protected: | |
91 using Type = EventOrReconnectionTimeSetting::Type; | |
92 EventSourceParserTest() | |
93 : m_client(new Client) | |
94 , m_parser(new EventSourceParser(AtomicString(), m_client)) | |
95 { | |
96 } | |
97 ~EventSourceParserTest() override {} | |
98 | |
99 void enqueue(const char* data) { m_parser->addBytes(data, strlen(data)); } | |
100 void enqueueOneByOne(const char* data) | |
101 { | |
102 const char*p = data; | |
103 while (*p != '\0') | |
104 m_parser->addBytes(p++, 1); | |
105 } | |
106 | |
107 const Vector<EventOrReconnectionTimeSetting>& events() { return m_client->ev ents(); } | |
108 | |
109 EventSourceParser* parser() { return m_parser; } | |
110 | |
111 Persistent<Client> m_client; | |
112 Persistent<EventSourceParser> m_parser; | |
113 }; | |
114 | |
115 TEST_F(EventSourceParserTest, EmptyMessageEventShouldNotBeDispatched) | |
116 { | |
117 enqueue("\n"); | |
118 | |
119 EXPECT_EQ(0u, events().size()); | |
120 EXPECT_EQ(String(), parser()->lastEventId()); | |
121 } | |
122 | |
123 TEST_F(EventSourceParserTest, DispatchSimpleMessageEvent) | |
124 { | |
125 enqueue("data:hello\n\n"); | |
126 | |
127 ASSERT_EQ(1u, events().size()); | |
128 ASSERT_EQ(Type::Event, events()[0].type); | |
129 EXPECT_EQ("message", events()[0].event); | |
130 EXPECT_EQ("hello", events()[0].data); | |
131 EXPECT_EQ(String(), events()[0].id); | |
132 EXPECT_EQ(AtomicString(), parser()->lastEventId()); | |
133 } | |
134 | |
135 TEST_F(EventSourceParserTest, ConstructWithLastEventId) | |
136 { | |
137 m_parser = new EventSourceParser("hoge", m_client); | |
138 EXPECT_EQ("hoge", parser()->lastEventId()); | |
139 | |
140 enqueue("data:hello\n\n"); | |
141 | |
142 ASSERT_EQ(1u, events().size()); | |
143 ASSERT_EQ(Type::Event, events()[0].type); | |
144 EXPECT_EQ("message", events()[0].event); | |
145 EXPECT_EQ("hello", events()[0].data); | |
146 EXPECT_EQ("hoge", events()[0].id); | |
147 EXPECT_EQ("hoge", parser()->lastEventId()); | |
148 } | |
149 | |
150 TEST_F(EventSourceParserTest, DispatchMessageEventWithLastEventId) | |
151 { | |
152 enqueue("id:99\ndata:hello\n"); | |
153 EXPECT_EQ(String(), parser()->lastEventId()); | |
154 | |
155 enqueue("\n"); | |
156 | |
157 ASSERT_EQ(1u, events().size()); | |
158 ASSERT_EQ(Type::Event, events()[0].type); | |
159 EXPECT_EQ("message", events()[0].event); | |
160 EXPECT_EQ("hello", events()[0].data); | |
161 EXPECT_EQ("99", events()[0].id); | |
162 EXPECT_EQ("99", parser()->lastEventId()); | |
163 } | |
164 | |
165 TEST_F(EventSourceParserTest, DispatchMessageEventWithCustomEventType) | |
166 { | |
167 enqueue("event:foo\ndata:hello\n\n"); | |
168 | |
169 ASSERT_EQ(1u, events().size()); | |
170 ASSERT_EQ(Type::Event, events()[0].type); | |
171 EXPECT_EQ("foo", events()[0].event); | |
172 EXPECT_EQ("hello", events()[0].data); | |
173 } | |
174 | |
175 TEST_F(EventSourceParserTest, RetryTakesEffectEvenWhenNotDispatching) | |
176 { | |
177 enqueue("retry:999\n"); | |
178 ASSERT_EQ(1u, events().size()); | |
179 ASSERT_EQ(Type::ReconnectionTimeSetting, events()[0].type); | |
180 ASSERT_EQ(999u, events()[0].reconnectionTime); | |
181 } | |
182 | |
183 TEST_F(EventSourceParserTest, EventTypeShouldBeReset) | |
184 { | |
185 enqueue("event:foo\ndata:hello\n\ndata:bye\n\n"); | |
186 | |
187 ASSERT_EQ(2u, events().size()); | |
188 ASSERT_EQ(Type::Event, events()[0].type); | |
189 EXPECT_EQ("foo", events()[0].event); | |
190 EXPECT_EQ("hello", events()[0].data); | |
191 | |
192 ASSERT_EQ(Type::Event, events()[1].type); | |
193 EXPECT_EQ("message", events()[1].event); | |
194 EXPECT_EQ("bye", events()[1].data); | |
195 } | |
196 | |
197 TEST_F(EventSourceParserTest, DataShouldBeReset) | |
198 { | |
199 enqueue("data:hello\n\n\n"); | |
200 | |
201 ASSERT_EQ(1u, events().size()); | |
202 ASSERT_EQ(Type::Event, events()[0].type); | |
203 EXPECT_EQ("message", events()[0].event); | |
204 EXPECT_EQ("hello", events()[0].data); | |
205 } | |
206 | |
207 TEST_F(EventSourceParserTest, LastEventIdShouldNotBeReset) | |
208 { | |
209 enqueue("id:99\ndata:hello\n\ndata:bye\n\n"); | |
210 | |
211 EXPECT_EQ("99", parser()->lastEventId()); | |
212 ASSERT_EQ(2u, events().size()); | |
213 ASSERT_EQ(Type::Event, events()[0].type); | |
214 EXPECT_EQ("message", events()[0].event); | |
215 EXPECT_EQ("hello", events()[0].data); | |
216 EXPECT_EQ("99", events()[0].id); | |
217 | |
218 ASSERT_EQ(Type::Event, events()[1].type); | |
219 EXPECT_EQ("message", events()[1].event); | |
220 EXPECT_EQ("bye", events()[1].data); | |
221 EXPECT_EQ("99", events()[1].id); | |
222 } | |
223 | |
224 TEST_F(EventSourceParserTest, VariousNewLinesShouldBeAllowed) | |
225 { | |
226 enqueueOneByOne("data:hello\r\n\rdata:bye\r\r"); | |
227 | |
228 ASSERT_EQ(2u, events().size()); | |
229 ASSERT_EQ(Type::Event, events()[0].type); | |
230 EXPECT_EQ("message", events()[0].event); | |
231 EXPECT_EQ("hello", events()[0].data); | |
232 | |
233 ASSERT_EQ(Type::Event, events()[1].type); | |
234 EXPECT_EQ("message", events()[1].event); | |
235 EXPECT_EQ("bye", events()[1].data); | |
236 } | |
237 | |
238 TEST_F(EventSourceParserTest, RetryWithEmptyValueShouldRestoreDefaultValue) | |
239 { | |
240 // TODO(yhirano): This is unspecified in the spec. We need to update | |
241 // the implementation or the spec. | |
242 enqueue("retry\n"); | |
243 ASSERT_EQ(1u, events().size()); | |
244 ASSERT_EQ(Type::ReconnectionTimeSetting, events()[0].type); | |
245 EXPECT_EQ(EventSource::defaultReconnectDelay, events()[0].reconnectionTime); | |
246 } | |
247 | |
248 TEST_F(EventSourceParserTest, NonDigitRetryShouldBeIgnored) | |
249 { | |
250 enqueue("retry:a0\n"); | |
251 enqueue("retry:xi\n"); | |
252 enqueue("retry:2a\n"); | |
253 enqueue("retry:09a\n"); | |
254 enqueue("retry:1\b\n"); | |
255 enqueue("retry: 1234\n"); | |
256 enqueue("retry:456 \n"); | |
257 | |
258 EXPECT_EQ(0u, events().size()); | |
259 } | |
260 | |
261 TEST_F(EventSourceParserTest, UnrecognizedFieldShouldBeIgnored) | |
262 { | |
263 enqueue("data:hello\nhoge:fuga\npiyo\n\n"); | |
264 | |
265 ASSERT_EQ(1u, events().size()); | |
266 ASSERT_EQ(Type::Event, events()[0].type); | |
267 EXPECT_EQ("message", events()[0].event); | |
268 EXPECT_EQ("hello", events()[0].data); | |
269 } | |
270 | |
271 TEST_F(EventSourceParserTest, CommentShouldBeIgnored) | |
272 { | |
273 enqueue("data:hello\n:event:a\n\n"); | |
274 | |
275 ASSERT_EQ(1u, events().size()); | |
276 ASSERT_EQ(Type::Event, events()[0].type); | |
277 EXPECT_EQ("message", events()[0].event); | |
278 EXPECT_EQ("hello", events()[0].data); | |
279 } | |
280 | |
281 TEST_F(EventSourceParserTest, BOMShouldBeIgnored) | |
282 { | |
283 // This line is recognized because "\xef\xbb\xbf" is a BOM. | |
284 enqueue("\xef\xbb\xbf" "data:hello\n"); | |
285 // This line is ignored because "\xef\xbb\xbf" is part of the field name. | |
286 enqueue("\xef\xbb\xbf" "data:bye\n"); | |
287 enqueue("\n"); | |
288 | |
289 ASSERT_EQ(1u, events().size()); | |
290 ASSERT_EQ(Type::Event, events()[0].type); | |
291 EXPECT_EQ("message", events()[0].event); | |
292 EXPECT_EQ("hello", events()[0].data); | |
293 } | |
tyoshino (SeeGerritForStatus)
2016/01/28 07:31:44
Please add BOM test that uses enqueueOneByOne()
yhirano
2016/01/28 08:45:36
Done.
| |
294 | |
295 TEST_F(EventSourceParserTest, ColonlessLineShouldBeTreatedAsNameOnlyField) | |
296 { | |
297 enqueue("data:hello\nevent:a\nevent\n\n"); | |
298 | |
299 ASSERT_EQ(1u, events().size()); | |
300 ASSERT_EQ(Type::Event, events()[0].type); | |
301 EXPECT_EQ("message", events()[0].event); | |
302 EXPECT_EQ("hello", events()[0].data); | |
303 } | |
304 | |
305 TEST_F(EventSourceParserTest, AtMostOneLeadingSpaceCanBeSkipped) | |
306 { | |
307 enqueue("data: hello \nevent: type \n\n"); | |
308 | |
309 ASSERT_EQ(1u, events().size()); | |
310 ASSERT_EQ(Type::Event, events()[0].type); | |
311 EXPECT_EQ(" type ", events()[0].event); | |
312 EXPECT_EQ(" hello ", events()[0].data); | |
313 } | |
314 | |
315 TEST_F(EventSourceParserTest, DataShouldAccumulate) | |
316 { | |
317 enqueue("data\ndata:hello\ndata: world\ndata\n\n"); | |
318 | |
319 ASSERT_EQ(1u, events().size()); | |
320 ASSERT_EQ(Type::Event, events()[0].type); | |
321 EXPECT_EQ("message", events()[0].event); | |
322 EXPECT_EQ("\nhello\nworld\n", events()[0].data); | |
323 } | |
324 | |
325 TEST_F(EventSourceParserTest, EventShouldNotAccumulate) | |
326 { | |
327 enqueue("data:hello\nevent:a\nevent:b\n\n"); | |
328 | |
329 ASSERT_EQ(1u, events().size()); | |
330 ASSERT_EQ(Type::Event, events()[0].type); | |
331 EXPECT_EQ("b", events()[0].event); | |
332 EXPECT_EQ("hello", events()[0].data); | |
333 } | |
334 | |
335 TEST_F(EventSourceParserTest, FeedDataOneByOne) | |
336 { | |
337 enqueueOneByOne("data:hello\r\ndata:world\revent:a\revent:b\nid:4\n\nid:8\nd ata:bye\r\n\r"); | |
338 | |
339 ASSERT_EQ(2u, events().size()); | |
340 ASSERT_EQ(Type::Event, events()[0].type); | |
341 EXPECT_EQ("b", events()[0].event); | |
342 EXPECT_EQ("hello\nworld", events()[0].data); | |
343 EXPECT_EQ("4", events()[0].id); | |
344 | |
345 ASSERT_EQ(Type::Event, events()[1].type); | |
346 EXPECT_EQ("message", events()[1].event); | |
347 EXPECT_EQ("bye", events()[1].data); | |
348 EXPECT_EQ("8", events()[1].id); | |
349 } | |
350 | |
351 TEST_F(EventSourceParserTest, InvalidUTF8Sequence) | |
352 { | |
353 enqueue("data:\xffhello\xc2\n\n"); | |
354 | |
355 ASSERT_EQ(1u, events().size()); | |
356 ASSERT_EQ(Type::Event, events()[0].type); | |
357 EXPECT_EQ("message", events()[0].event); | |
358 String expected = String() + replacementCharacter + "hello" + replacementCha racter; | |
359 EXPECT_EQ(expected, events()[0].data); | |
360 } | |
361 | |
362 TEST(EventSourceParserStoppingTest, Stop) | |
363 { | |
364 StoppingClient* client = new StoppingClient(); | |
365 EventSourceParser* parser = new EventSourceParser(AtomicString(), client); | |
366 client->setParser(parser); | |
367 | |
368 const char input[] = "data:hello\n\ndata:bye\n\n"; | |
369 parser->addBytes(input, strlen(input)); | |
370 | |
371 const auto& events = client->events(); | |
372 | |
373 ASSERT_EQ(1u, events.size()); | |
374 ASSERT_EQ(EventOrReconnectionTimeSetting::Type::Event, events[0].type); | |
375 EXPECT_EQ("message", events[0].event); | |
376 EXPECT_EQ("hello", events[0].data); | |
377 } | |
378 | |
379 } // namespace | |
380 | |
381 } // namespace blink | |
OLD | NEW |