Skip to content

Commit

Permalink
make to_string a proper method of replace::Data
Browse files Browse the repository at this point in the history
  • Loading branch information
saites committed Oct 30, 2024
1 parent 3fda0ca commit c34580f
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 33 deletions.
2 changes: 1 addition & 1 deletion crates/rustfix/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ impl<'orig> CodeFix<'orig> {

/// Gets the result of the "fixed" code.
pub fn finish(&self) -> Result<String, Error> {
Ok(String::from_utf8(self.data.to_vec())?)
self.data.to_string()
}

/// Returns whether or not the data has been modified.
Expand Down
68 changes: 36 additions & 32 deletions crates/rustfix/src/replace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
//! which will validate that the changes do not conflict with one another.
//! At any time, you can "checkpoint" the current changes with [`Data::commit`]
//! or roll them back (perhaps due to a conflict) with [`Data::restore`].
//! When you're done, use [`Data::to_vec`]
//! When you're done, use [`Data::to_vec`] or [`Data::to_string`]
//! to merge the original data with the changes.
//!
//! # Notes
//!
//! The [`Data::to_vec`] method includes uncommitted changes, if present.
//! The [`Data::to_vec`] and [`Data::to_string`] methods include uncommitted changes, if present.
//! The reason for including uncommitted changes is that typically, once you're calling those,
//! you're done with edits and will be dropping the [`Data`] struct in a moment.
//! In this case, requiring an extra call to `commit` would be unnecessary work.
Expand Down Expand Up @@ -138,6 +138,14 @@ impl<'orig> Data<'orig> {
s
}

/// Merge the original data with changes, **including** uncommitted changes,
/// and validate that the result is a valid UTF-8 string.
///
/// See the module-level documentation for more information on why uncommitted changes are included.
pub fn to_string(&self) -> Result<String, Error> {
Ok(String::from_utf8(self.to_vec())?)
}

/// Record a provisional change.
///
/// If committed, the original data in the given `range` will be replaced by the given data.
Expand Down Expand Up @@ -198,61 +206,57 @@ mod tests {
use super::*;
use proptest::prelude::*;

fn str(i: &[u8]) -> &str {
::std::str::from_utf8(i).unwrap()
}

#[test]
fn insert_at_beginning() {
let mut d = Data::new("foo bar baz");
d.replace_range(0..0, "oh no ").unwrap();
assert_eq!("oh no foo bar baz", str(&d.to_vec()));
assert_eq!("oh no foo bar baz", &d.to_string().unwrap());
}

#[test]
fn insert_at_end() {
let mut d = Data::new("foo bar baz");
d.replace_range(11..11, " oh no").unwrap();
assert_eq!("foo bar baz oh no", str(&d.to_vec()));
assert_eq!("foo bar baz oh no", &d.to_string().unwrap());
}

#[test]
fn replace_some_stuff() {
let mut d = Data::new("foo bar baz");
d.replace_range(4..7, "lol").unwrap();
assert_eq!("foo lol baz", str(&d.to_vec()));
assert_eq!("foo lol baz", &d.to_string().unwrap());
}

#[test]
fn replace_a_single_char() {
let mut d = Data::new("let y = true;");
d.replace_range(4..5, "mut y").unwrap();
assert_eq!("let mut y = true;", str(&d.to_vec()));
assert_eq!("let mut y = true;", &d.to_string().unwrap());
}

#[test]
fn replace_multiple_lines() {
let mut d = Data::new("lorem\nipsum\ndolor");

d.replace_range(6..11, "lol").unwrap();
assert_eq!("lorem\nlol\ndolor", str(&d.to_vec()));
assert_eq!("lorem\nlol\ndolor", &d.to_string().unwrap());

d.replace_range(12..17, "lol").unwrap();
assert_eq!("lorem\nlol\nlol", str(&d.to_vec()));
assert_eq!("lorem\nlol\nlol", &d.to_string().unwrap());
}

#[test]
fn replace_multiple_lines_with_insert_only() {
let mut d = Data::new("foo!");

d.replace_range(3..3, "bar").unwrap();
assert_eq!("foobar!", str(&d.to_vec()));
assert_eq!("foobar!", &d.to_string().unwrap());

d.replace_range(0..3, "baz").unwrap();
assert_eq!("bazbar!", str(&d.to_vec()));
assert_eq!("bazbar!", &d.to_string().unwrap());

d.replace_range(3..4, "?").unwrap();
assert_eq!("bazbar?", str(&d.to_vec()));
assert_eq!("bazbar?", &d.to_string().unwrap());
}

#[test]
Expand All @@ -264,17 +268,17 @@ mod tests {
}

#[test]
fn empty_to_vec_roundtrip() {
fn empty_to_string_roundtrip() {
let s = "";
assert_eq!(s.as_bytes(), Data::new(s.as_bytes()).to_vec().as_slice());
assert_eq!(s, &Data::new(s).to_string().unwrap());
}

#[test]
fn replace_same_range_diff_data() {
let mut d = Data::new("foo bar baz");

d.replace_range(4..7, "lol").unwrap();
assert_eq!("foo lol baz", str(&d.to_vec()));
assert_eq!("foo lol baz", &d.to_string().unwrap());

assert!(matches!(
d.replace_range(4..7, "lol2").unwrap_err(),
Expand All @@ -290,7 +294,7 @@ mod tests {
let mut d = Data::new("foo bar baz");

d.replace_range(4..7, "lol").unwrap();
assert_eq!("foo lol baz", str(&d.to_vec()));
assert_eq!("foo lol baz", &d.to_string().unwrap());

assert!(matches!(
d.replace_range(4..7, "lol").unwrap_err(),
Expand All @@ -314,50 +318,50 @@ mod tests {
fn insert_same_twice() {
let mut d = Data::new("foo");
d.replace_range(1..1, "b").unwrap();
assert_eq!("fboo", str(&d.to_vec()));
assert_eq!("fboo", &d.to_string().unwrap());
assert!(matches!(
d.replace_range(1..1, "b").unwrap_err(),
Error::AlreadyReplaced {
is_identical: true,
..
},
));
assert_eq!("fboo", str(&d.to_vec()));
assert_eq!("fboo", &d.to_string().unwrap());
}

#[test]
fn commit_restore() {
let mut d = Data::new(", ");
assert_eq!(", ", str(&d.to_vec()));
assert_eq!(", ", &d.to_string().unwrap());

d.replace_range(2..2, "world").unwrap();
d.replace_range(0..0, "hello").unwrap();
assert_eq!("hello, world", str(&d.to_vec()));
assert_eq!("hello, world", &d.to_string().unwrap());

d.restore();
assert_eq!(", ", str(&d.to_vec()));
assert_eq!(", ", &d.to_string().unwrap());

d.commit();
assert_eq!(", ", str(&d.to_vec()));
assert_eq!(", ", &d.to_string().unwrap());

d.replace_range(2..2, "world").unwrap();
assert_eq!(", world", str(&d.to_vec()));
assert_eq!(", world", &d.to_string().unwrap());
d.commit();
assert_eq!(", world", str(&d.to_vec()));
assert_eq!(", world", &d.to_string().unwrap());
d.restore();
assert_eq!(", world", str(&d.to_vec()));
assert_eq!(", world", &d.to_string().unwrap());

d.replace_range(0..0, "hello").unwrap();
assert_eq!("hello, world", str(&d.to_vec()));
assert_eq!("hello, world", &d.to_string().unwrap());
d.commit();
assert_eq!("hello, world", str(&d.to_vec()));
assert_eq!("hello, world", &d.to_string().unwrap());
d.restore();
assert_eq!("hello, world", str(&d.to_vec()));
assert_eq!("hello, world", &d.to_string().unwrap());
}

proptest! {
#[test]
fn new_to_vec_roundtrip(ref s in "\\PC*") {
fn new_to_string_roundtrip(ref s in "\\PC*") {
assert_eq!(s.as_bytes(), &Data::new(s).to_vec());
}

Expand Down

0 comments on commit c34580f

Please sign in to comment.