Refactor tests
diff --git a/Cargo.toml b/Cargo.toml
index 643422d..7ef2aa4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -28,3 +28,4 @@
 
 [dev-dependencies]
 tempdir = "0.3"
+assert_matches = "1.2"
diff --git a/src/edit.rs b/src/edit.rs
index 045ed3a..0cce2b6 100644
--- a/src/edit.rs
+++ b/src/edit.rs
@@ -493,10 +493,11 @@
 mod test {
     use super::init_state;
     use history::History;
+    use tty::Sink;
 
     #[test]
     fn edit_history_next() {
-        let mut out = ::std::io::sink();
+        let mut out = Sink::new();
         let line = "current edited line";
         let mut s = init_state(&mut out, line, 6);
         let mut history = History::new();
diff --git a/src/keymap.rs b/src/keymap.rs
index 9656e3a..e08838f 100644
--- a/src/keymap.rs
+++ b/src/keymap.rs
@@ -813,9 +813,9 @@
             KeyPress::Ctrl('T') => Cmd::TransposeChars,
             KeyPress::Ctrl('U') => {
                 if positive {
-                Cmd::Kill(Movement::BeginningOfLine)
+                    Cmd::Kill(Movement::BeginningOfLine)
                 } else {
-                Cmd::Kill(Movement::EndOfLine)
+                    Cmd::Kill(Movement::EndOfLine)
                 }
             },
             KeyPress::Ctrl('Q') | // most terminals override Ctrl+Q to resume execution
diff --git a/src/lib.rs b/src/lib.rs
index e898b34..903fbaa 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -802,122 +802,7 @@
 }
 
 #[cfg(test)]
-mod test {
-    use std::cell::RefCell;
-    use std::collections::HashMap;
-    use std::rc::Rc;
-
-    use super::{Editor, Result};
-    use completion::Completer;
-    use config::Config;
-    use consts::KeyPress;
-    use edit::init_state;
-    use keymap::{Cmd, InputState};
-
-    fn init_editor(keys: &[KeyPress]) -> Editor<()> {
-        let mut editor = Editor::<()>::new();
-        editor.term.keys.extend(keys.iter().cloned());
-        editor
-    }
-
-    struct SimpleCompleter;
-    impl Completer for SimpleCompleter {
-        fn complete(&self, line: &str, _pos: usize) -> Result<(usize, Vec<String>)> {
-            Ok((0, vec![line.to_owned() + "t"]))
-        }
-    }
-
-    #[test]
-    fn complete_line() {
-        let mut out = ::std::io::sink();
-        let mut s = init_state(&mut out, "rus", 3);
-        let config = Config::default();
-        let mut input_state = InputState::new(&config, Rc::new(RefCell::new(HashMap::new())));
-        let keys = &[KeyPress::Enter];
-        let mut rdr = keys.iter();
-        let completer = SimpleCompleter;
-        let cmd = super::complete_line(
-            &mut rdr,
-            &mut s,
-            &mut input_state,
-            &completer,
-            &Config::default(),
-        ).unwrap();
-        assert_eq!(Some(Cmd::AcceptLine), cmd);
-        assert_eq!("rust", s.line.as_str());
-        assert_eq!(4, s.line.pos());
-    }
-
-    fn assert_line(keys: &[KeyPress], expected_line: &str) {
-        let mut editor = init_editor(keys);
-        let actual_line = editor.readline(&">>").unwrap();
-        assert_eq!(expected_line, actual_line);
-    }
-
-    #[test]
-    fn delete_key() {
-        assert_line(
-            &[KeyPress::Char('a'), KeyPress::Delete, KeyPress::Enter],
-            "a",
-        );
-        assert_line(
-            &[
-                KeyPress::Char('a'),
-                KeyPress::Left,
-                KeyPress::Delete,
-                KeyPress::Enter,
-            ],
-            "",
-        );
-    }
-
-    #[test]
-    fn down_key() {
-        assert_line(&[KeyPress::Down, KeyPress::Enter], "");
-    }
-
-    #[test]
-    fn end_key() {
-        assert_line(&[KeyPress::End, KeyPress::Enter], "");
-    }
-
-    #[test]
-    fn home_key() {
-        assert_line(&[KeyPress::Home, KeyPress::Enter], "");
-    }
-
-    #[test]
-    fn left_key() {
-        assert_line(&[KeyPress::Left, KeyPress::Enter], "");
-    }
-
-    #[test]
-    fn meta_backspace_key() {
-        assert_line(&[KeyPress::Meta('\x08'), KeyPress::Enter], "");
-    }
-
-    #[test]
-    fn page_down_key() {
-        assert_line(&[KeyPress::PageDown, KeyPress::Enter], "");
-    }
-
-    #[test]
-    fn page_up_key() {
-        assert_line(&[KeyPress::PageUp, KeyPress::Enter], "");
-    }
-
-    #[test]
-    fn right_key() {
-        assert_line(&[KeyPress::Right, KeyPress::Enter], "");
-    }
-
-    #[test]
-    fn up_key() {
-        assert_line(&[KeyPress::Up, KeyPress::Enter], "");
-    }
-
-    #[test]
-    fn unknown_esc_key() {
-        assert_line(&[KeyPress::UnknownEscSeq, KeyPress::Enter], "");
-    }
-}
+#[macro_use]
+extern crate assert_matches;
+#[cfg(test)]
+mod test;
diff --git a/src/test/common.rs b/src/test/common.rs
new file mode 100644
index 0000000..8205bc2
--- /dev/null
+++ b/src/test/common.rs
@@ -0,0 +1,112 @@
+use super::{assert_cursor, assert_line, assert_line_with_initial, init_editor};
+use consts::KeyPress;
+use error::ReadlineError;
+
+#[test]
+fn home_key() {
+    assert_cursor(("", ""), &[KeyPress::Home, KeyPress::Enter], 0);
+    assert_cursor(("Hi", ""), &[KeyPress::Home, KeyPress::Enter], 0);
+}
+
+#[test]
+fn end_key() {
+    assert_cursor(("", ""), &[KeyPress::End, KeyPress::Enter], 0);
+    //assert_cursor(("H", "i"), &[KeyPress::End, KeyPress::Enter], 2); FIXME
+}
+
+#[test]
+fn left_key() {
+    assert_cursor(("Hi", ""), &[KeyPress::Left, KeyPress::Enter], 1);
+    assert_cursor(("H", "i"), &[KeyPress::Left, KeyPress::Enter], 0);
+    assert_cursor(("", "Hi"), &[KeyPress::Left, KeyPress::Enter], 0);
+}
+
+#[test]
+fn right_key() {
+    assert_cursor(("", ""), &[KeyPress::Right, KeyPress::Enter], 0);
+    assert_cursor(("", "Hi"), &[KeyPress::Right, KeyPress::Enter], 1);
+    assert_cursor(("B", "ye"), &[KeyPress::Right, KeyPress::Enter], 2);
+}
+
+#[test]
+fn enter_key() {
+    assert_line(&[KeyPress::Enter], "");
+    assert_line(&[KeyPress::Char('a'), KeyPress::Enter], "a");
+    assert_line_with_initial(("Hi", ""), &[KeyPress::Enter], "Hi");
+    assert_line_with_initial(("", "Hi"), &[KeyPress::Enter], "Hi");
+    assert_line_with_initial(("H", "i"), &[KeyPress::Enter], "Hi");
+}
+
+#[test]
+fn newline_key() {
+    assert_line(&[KeyPress::Ctrl('J')], "");
+    assert_line(&[KeyPress::Char('a'), KeyPress::Ctrl('J')], "a");
+}
+
+#[test]
+fn eof_key() {
+    let mut editor = init_editor(&[KeyPress::Ctrl('D')]);
+    let err = editor.readline(">>");
+    assert_matches!(err, Err(ReadlineError::Eof));
+
+    assert_line(
+        &[KeyPress::Char('a'), KeyPress::Ctrl('D'), KeyPress::Enter],
+        "a",
+    );
+    assert_line_with_initial(("", "Hi"), &[KeyPress::Ctrl('D'), KeyPress::Enter], "i");
+}
+
+#[test]
+fn interrupt_key() {
+    let mut editor = init_editor(&[KeyPress::Ctrl('C')]);
+    let err = editor.readline(">>");
+    assert_matches!(err, Err(ReadlineError::Interrupted));
+
+    let mut editor = init_editor(&[KeyPress::Ctrl('C')]);
+    let err = editor.readline_with_initial(">>", ("Hi", ""));
+    assert_matches!(err, Err(ReadlineError::Interrupted));
+}
+
+#[test]
+fn delete_key() {
+    assert_line_with_initial(("a", ""), &[KeyPress::Delete, KeyPress::Enter], "a");
+    assert_line_with_initial(("", "a"), &[KeyPress::Delete, KeyPress::Enter], "");
+}
+
+#[test]
+fn ctrl_t() {
+    assert_line_with_initial(("a", "b"), &[KeyPress::Ctrl('T'), KeyPress::Enter], "ba");
+    assert_line_with_initial(
+        ("ab", "cd"),
+        &[KeyPress::Ctrl('T'), KeyPress::Enter],
+        "acbd",
+    );
+}
+
+#[test]
+fn ctrl_u() {
+    assert_line_with_initial(("a", "b"), &[KeyPress::Ctrl('U'), KeyPress::Enter], "b");
+    assert_line_with_initial(("", "a"), &[KeyPress::Ctrl('U'), KeyPress::Enter], "a");
+}
+
+#[test]
+fn ctrl_v() {
+    assert_line(
+        &[KeyPress::Ctrl('V'), KeyPress::Char('\t'), KeyPress::Enter],
+        "\t",
+    );
+}
+
+#[test]
+fn ctrl_w() {
+    assert_line_with_initial(
+        ("Hello, ", "world"),
+        &[KeyPress::Ctrl('W'), KeyPress::Enter],
+        "world",
+    );
+    assert_line_with_initial(
+        ("Hello, world.", ""),
+        &[KeyPress::Ctrl('W'), KeyPress::Enter],
+        "Hello, ",
+    );
+}
diff --git a/src/test/mod.rs b/src/test/mod.rs
new file mode 100644
index 0000000..b741868
--- /dev/null
+++ b/src/test/mod.rs
@@ -0,0 +1,93 @@
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::rc::Rc;
+
+use super::{Editor, Result};
+use completion::Completer;
+use config::Config;
+use consts::KeyPress;
+use edit::init_state;
+use keymap::{Cmd, InputState};
+use tty::Sink;
+
+mod common;
+
+fn init_editor(keys: &[KeyPress]) -> Editor<()> {
+    let mut editor = Editor::<()>::new();
+    editor.term.keys.extend(keys.iter().cloned());
+    editor
+}
+
+struct SimpleCompleter;
+impl Completer for SimpleCompleter {
+    fn complete(&self, line: &str, _pos: usize) -> Result<(usize, Vec<String>)> {
+        Ok((0, vec![line.to_owned() + "t"]))
+    }
+}
+
+#[test]
+fn complete_line() {
+    let mut out = Sink::new();
+    let mut s = init_state(&mut out, "rus", 3);
+    let config = Config::default();
+    let mut input_state = InputState::new(&config, Rc::new(RefCell::new(HashMap::new())));
+    let keys = &[KeyPress::Enter];
+    let mut rdr = keys.iter();
+    let completer = SimpleCompleter;
+    let cmd = super::complete_line(
+        &mut rdr,
+        &mut s,
+        &mut input_state,
+        &completer,
+        &Config::default(),
+    ).unwrap();
+    assert_eq!(Some(Cmd::AcceptLine), cmd);
+    assert_eq!("rust", s.line.as_str());
+    assert_eq!(4, s.line.pos());
+}
+
+fn assert_line(keys: &[KeyPress], expected_line: &str) {
+    let mut editor = init_editor(keys);
+    let actual_line = editor.readline(">>").unwrap();
+    assert_eq!(expected_line, actual_line);
+}
+fn assert_line_with_initial(initial: (&str, &str), keys: &[KeyPress], expected_line: &str) {
+    let mut editor = init_editor(keys);
+    let actual_line = editor.readline_with_initial(">>", initial).unwrap();
+    assert_eq!(expected_line, actual_line);
+}
+fn assert_cursor(initial: (&str, &str), keys: &[KeyPress], expected_cursor: usize) {
+    let mut editor = init_editor(keys);
+    editor.readline_with_initial("", initial).unwrap();
+    assert_eq!(expected_cursor, editor.term.cursor.get());
+}
+
+#[test]
+fn down_key() {
+    assert_line(&[KeyPress::Down, KeyPress::Enter], "");
+}
+
+#[test]
+fn meta_backspace_key() {
+    assert_line(&[KeyPress::Meta('\x08'), KeyPress::Enter], "");
+}
+
+#[test]
+fn page_down_key() {
+    assert_line(&[KeyPress::PageDown, KeyPress::Enter], "");
+}
+
+#[test]
+fn page_up_key() {
+    assert_line(&[KeyPress::PageUp, KeyPress::Enter], "");
+}
+
+#[test]
+fn up_key() {
+    assert_line(&[KeyPress::Up, KeyPress::Enter], "");
+}
+
+#[test]
+fn unknown_esc_key() {
+    assert_line(&[KeyPress::UnknownEscSeq, KeyPress::Enter], "");
+}
diff --git a/src/tty/test.rs b/src/tty/test.rs
index 7a19c9a..3d7933f 100644
--- a/src/tty/test.rs
+++ b/src/tty/test.rs
@@ -1,6 +1,7 @@
 //! Tests specific definitions
-use std::io::{self, Sink, Write};
+use std::cell::Cell;
 use std::iter::IntoIterator;
+use std::rc::Rc;
 use std::slice::Iter;
 use std::vec::IntoIter;
 
@@ -41,40 +42,60 @@
     }
     #[cfg(unix)]
     fn next_char(&mut self) -> Result<char> {
-        unimplemented!();
+        match self.next() {
+            Some(KeyPress::Char(c)) => Ok(c),
+            None => Err(ReadlineError::Eof),
+            _ => unimplemented!(),
+        }
+    }
+}
+
+pub struct Sink {
+    cursor: Rc<Cell<usize>>, // cursor position before last command
+    last: usize,
+}
+
+impl Sink {
+    pub fn new() -> Sink {
+        Sink {
+            cursor: Rc::new(Cell::new(0)),
+            last: 0,
+        }
     }
 }
 
 impl Renderer for Sink {
-    fn move_cursor(&mut self, _: Position, _: Position) -> Result<()> {
+    fn move_cursor(&mut self, _: Position, new: Position) -> Result<()> {
+        self.cursor.replace(self.last);
+        self.last = new.col;
         Ok(())
     }
 
     fn refresh_line(
         &mut self,
-        prompt: &str,
+        _: &str,
         prompt_size: Position,
         line: &LineBuffer,
         hint: Option<String>,
         _: usize,
         _: usize,
     ) -> Result<(Position, Position)> {
-        try!(self.write_all(prompt.as_bytes()));
-        try!(self.write_all(line.as_bytes()));
+        let cursor = self.calculate_position(&line[..line.pos()], prompt_size);
+        self.last = cursor.col;
         if let Some(hint) = hint {
-            try!(self.write_all(truncate(&hint, 0, 80).as_bytes()));
+            truncate(&hint, 0, 80);
         }
-        Ok((prompt_size, prompt_size))
+        let end = self.calculate_position(&line, prompt_size);
+        Ok((cursor, end))
     }
 
-    /// Characters with 2 column width are correctly handled (not splitted).
-    fn calculate_position(&self, _: &str, orig: Position) -> Position {
-        orig
+    fn calculate_position(&self, s: &str, orig: Position) -> Position {
+        let mut pos = orig;
+        pos.col += s.len();
+        pos
     }
 
-    fn write_and_flush(&mut self, buf: &[u8]) -> Result<()> {
-        try!(self.write_all(buf));
-        try!(self.flush());
+    fn write_and_flush(&mut self, _: &[u8]) -> Result<()> {
         Ok(())
     }
 
@@ -82,12 +103,10 @@
         Ok(())
     }
 
-    /// Clear the screen. Used to handle ctrl+l
     fn clear_screen(&mut self) -> Result<()> {
         Ok(())
     }
 
-    /// Check if a SIGWINCH signal has been received
     fn sigwinch(&self) -> bool {
         false
     }
@@ -105,6 +124,7 @@
 #[derive(Clone, Debug)]
 pub struct DummyTerminal {
     pub keys: Vec<KeyPress>,
+    pub cursor: Rc<Cell<usize>>, // cursor position before last command
 }
 
 impl Term for DummyTerminal {
@@ -113,18 +133,18 @@
     type Mode = Mode;
 
     fn new() -> DummyTerminal {
-        DummyTerminal { keys: Vec::new() }
+        DummyTerminal {
+            keys: Vec::new(),
+            cursor: Rc::new(Cell::new(0)),
+        }
     }
 
     // Init checks:
 
-    /// Check if current terminal can provide a rich line-editing user
-    /// interface.
     fn is_unsupported(&self) -> bool {
         false
     }
 
-    /// check if stdin is connected to a terminal.
     fn is_stdin_tty(&self) -> bool {
         true
     }
@@ -135,13 +155,15 @@
         Ok(())
     }
 
-    /// Create a RAW reader
     fn create_reader(&self, _: &Config) -> Result<IntoIter<KeyPress>> {
         Ok(self.keys.clone().into_iter())
     }
 
     fn create_writer(&self) -> Sink {
-        io::sink()
+        Sink {
+            cursor: self.cursor.clone(),
+            last: 0,
+        }
     }
 }