@@ -153,4 +153,144 @@ public function testMovingCursorWithoutEchoDoesNotNeedToRedraw()
153153 $ this ->assertSame ($ this ->readline , $ this ->readline ->moveCursorTo (0 ));
154154 $ this ->assertSame ($ this ->readline , $ this ->readline ->moveCursorBy (2 ));
155155 }
156+
157+ public function testWriteSimpleCharWritesOnce ()
158+ {
159+ $ this ->output ->expects ($ this ->once ())->method ('write ' )->with ($ this ->equalTo ("\r\033[K " . "k " ));
160+
161+ $ this ->pushInputBytes ($ this ->readline , 'k ' );
162+ }
163+
164+ public function testWriteMultiByteCharWritesOnce ()
165+ {
166+ $ this ->output ->expects ($ this ->once ())->method ('write ' )->with ($ this ->equalTo ("\r\033[K " . "\xF0\x9D\x84\x9E" ));
167+
168+ // "𝄞" – U+1D11E MUSICAL SYMBOL G CLEF
169+ $ this ->pushInputBytes ($ this ->readline , "\xF0\x9D\x84\x9E" );
170+ }
171+
172+ public function testKeysSimpleChars ()
173+ {
174+ $ this ->pushInputBytes ($ this ->readline , 'hi! ' );
175+
176+ $ this ->assertEquals ('hi! ' , $ this ->readline ->getInput ());
177+ $ this ->assertEquals (3 , $ this ->readline ->getCursorPosition ());
178+
179+ return $ this ->readline ;
180+ }
181+
182+ /**
183+ * @depends testKeysSimpleChars
184+ * @param Readline $readline
185+ */
186+ public function testKeysBackspaceDeletesLastCharacter (Readline $ readline )
187+ {
188+ $ readline ->onKeyBackspace ();
189+
190+ $ this ->assertEquals ('hi ' , $ readline ->getInput ());
191+ $ this ->assertEquals (2 , $ readline ->getCursorPosition ());
192+ }
193+
194+ public function testKeysMultiByteInput ()
195+ {
196+ $ this ->pushInputBytes ($ this ->readline , 'hä ' );
197+
198+ $ this ->assertEquals ('hä ' , $ this ->readline ->getInput ());
199+ $ this ->assertEquals (2 , $ this ->readline ->getCursorPosition ());
200+
201+ return $ this ->readline ;
202+ }
203+
204+ /**
205+ * @depends testKeysMultiByteInput
206+ * @param Readline $readline
207+ */
208+ public function testKeysBackspaceDeletesWholeMultibyteCharacter (Readline $ readline )
209+ {
210+ $ readline ->onKeyBackspace ();
211+
212+ $ this ->assertEquals ('h ' , $ readline ->getInput ());
213+ }
214+
215+ public function testKeysBackspaceMiddle ()
216+ {
217+ $ this ->readline ->setInput ('test ' );
218+ $ this ->readline ->moveCursorTo (2 );
219+
220+ $ this ->readline ->onKeyBackspace ();
221+
222+ $ this ->assertEquals ('tst ' , $ this ->readline ->getInput ());
223+ $ this ->assertEquals (1 , $ this ->readline ->getCursorPosition ());
224+ }
225+
226+ public function testKeysBackspaceFrontDoesNothing ()
227+ {
228+ $ this ->readline ->setInput ('test ' );
229+ $ this ->readline ->moveCursorTo (0 );
230+
231+ $ this ->readline ->onKeyBackspace ();
232+
233+ $ this ->assertEquals ('test ' , $ this ->readline ->getInput ());
234+ $ this ->assertEquals (0 , $ this ->readline ->getCursorPosition ());
235+ }
236+
237+ public function testKeysDeleteMiddle ()
238+ {
239+ $ this ->readline ->setInput ('test ' );
240+ $ this ->readline ->moveCursorTo (2 );
241+
242+ $ this ->readline ->onKeyDelete ();
243+
244+ $ this ->assertEquals ('tet ' , $ this ->readline ->getInput ());
245+ $ this ->assertEquals (2 , $ this ->readline ->getCursorPosition ());
246+ }
247+
248+ public function testKeysDeleteEndDoesNothing ()
249+ {
250+ $ this ->readline ->setInput ('test ' );
251+
252+ $ this ->readline ->onKeyDelete ();
253+
254+ $ this ->assertEquals ('test ' , $ this ->readline ->getInput ());
255+ $ this ->assertEquals (4 , $ this ->readline ->getCursorPosition ());
256+ }
257+
258+ public function testKeysPrependCharacterInFrontOfMultiByte ()
259+ {
260+ $ this ->readline ->setInput ('ü ' );
261+ $ this ->readline ->moveCursorTo (0 );
262+
263+ $ this ->pushInputBytes ($ this ->readline , 'h ' );
264+
265+ $ this ->assertEquals ('hü ' , $ this ->readline ->getInput ());
266+ $ this ->assertEquals (1 , $ this ->readline ->getCursorPosition ());
267+ }
268+
269+ public function testKeysWriteMultiByteAfterMultiByte ()
270+ {
271+ $ this ->readline ->setInput ('ü ' );
272+
273+ $ this ->pushInputBytes ($ this ->readline , 'ä ' );
274+
275+ $ this ->assertEquals ('üä ' , $ this ->readline ->getInput ());
276+ $ this ->assertEquals (2 , $ this ->readline ->getCursorPosition ());
277+ }
278+
279+ public function testKeysPrependMultiByteInFrontOfMultiByte ()
280+ {
281+ $ this ->readline ->setInput ('ü ' );
282+ $ this ->readline ->moveCursorTo (0 );
283+
284+ $ this ->pushInputBytes ($ this ->readline , 'ä ' );
285+
286+ $ this ->assertEquals ('äü ' , $ this ->readline ->getInput ());
287+ $ this ->assertEquals (1 , $ this ->readline ->getCursorPosition ());
288+ }
289+
290+ private function pushInputBytes (Readline $ readline , $ bytes )
291+ {
292+ foreach (str_split ($ bytes , 1 ) as $ byte ) {
293+ $ readline ->onChar ($ byte );
294+ }
295+ }
156296}
0 commit comments