diff options
Diffstat (limited to 'crates/ra_text_edit')
-rw-r--r-- | crates/ra_text_edit/src/test_utils.rs | 72 | ||||
-rw-r--r-- | crates/ra_text_edit/src/text_edit.rs | 15 |
2 files changed, 28 insertions, 59 deletions
diff --git a/crates/ra_text_edit/src/test_utils.rs b/crates/ra_text_edit/src/test_utils.rs index f150288f6..f0b8dfde1 100644 --- a/crates/ra_text_edit/src/test_utils.rs +++ b/crates/ra_text_edit/src/test_utils.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use proptest::prelude::*; | 1 | use proptest::prelude::*; |
2 | use text_unit::{TextUnit, TextRange}; | 2 | use text_unit::{TextUnit, TextRange}; |
3 | use crate::AtomTextEdit; | 3 | use crate::{AtomTextEdit, TextEdit}; |
4 | 4 | ||
5 | pub fn arb_text() -> proptest::string::RegexGeneratorStrategy<String> { | 5 | pub fn arb_text() -> proptest::string::RegexGeneratorStrategy<String> { |
6 | // generate multiple newlines | 6 | // generate multiple newlines |
@@ -23,11 +23,7 @@ pub fn arb_offset(text: &str) -> BoxedStrategy<TextUnit> { | |||
23 | } | 23 | } |
24 | } | 24 | } |
25 | 25 | ||
26 | pub fn arb_edits(text: &str) -> BoxedStrategy<Vec<AtomTextEdit>> { | 26 | pub fn arb_text_edit(text: &str) -> BoxedStrategy<TextEdit> { |
27 | arb_edits_custom(&text, 0, 7) | ||
28 | } | ||
29 | |||
30 | pub fn arb_edits_custom(text: &str, min: usize, max: usize) -> BoxedStrategy<Vec<AtomTextEdit>> { | ||
31 | if text.is_empty() { | 27 | if text.is_empty() { |
32 | // only valid edits | 28 | // only valid edits |
33 | return Just(vec![]) | 29 | return Just(vec![]) |
@@ -37,14 +33,14 @@ pub fn arb_edits_custom(text: &str, min: usize, max: usize) -> BoxedStrategy<Vec | |||
37 | .prop_map(|text| vec![AtomTextEdit::insert(TextUnit::from(0), text)]) | 33 | .prop_map(|text| vec![AtomTextEdit::insert(TextUnit::from(0), text)]) |
38 | .boxed(), | 34 | .boxed(), |
39 | ) | 35 | ) |
36 | .prop_map(TextEdit::from_atoms) | ||
40 | .boxed(); | 37 | .boxed(); |
41 | } | 38 | } |
42 | 39 | ||
43 | let offsets = text_offsets(text); | 40 | let offsets = text_offsets(text); |
44 | let max_cuts = max.min(offsets.len()); | 41 | let max_cuts = 7.min(offsets.len()); |
45 | let min_cuts = min.min(offsets.len() - 1); | ||
46 | 42 | ||
47 | proptest::sample::subsequence(offsets, min_cuts..max_cuts) | 43 | proptest::sample::subsequence(offsets, 0..max_cuts) |
48 | .prop_flat_map(|cuts| { | 44 | .prop_flat_map(|cuts| { |
49 | let strategies: Vec<_> = cuts | 45 | let strategies: Vec<_> = cuts |
50 | .chunks(2) | 46 | .chunks(2) |
@@ -68,52 +64,22 @@ pub fn arb_edits_custom(text: &str, min: usize, max: usize) -> BoxedStrategy<Vec | |||
68 | .collect(); | 64 | .collect(); |
69 | strategies | 65 | strategies |
70 | }) | 66 | }) |
67 | .prop_map(TextEdit::from_atoms) | ||
71 | .boxed() | 68 | .boxed() |
72 | } | 69 | } |
73 | 70 | ||
74 | #[cfg(test)] | 71 | #[derive(Debug, Clone)] |
75 | mod tests { | 72 | pub struct ArbTextWithEdits { |
76 | use super::*; | 73 | pub text: String, |
77 | use proptest::{proptest, proptest_helper}; | 74 | pub edits: TextEdit, |
78 | 75 | } | |
79 | fn arb_text_with_edits() -> BoxedStrategy<(String, Vec<AtomTextEdit>)> { | ||
80 | let text = arb_text(); | ||
81 | text.prop_flat_map(|s| { | ||
82 | let edits = arb_edits(&s); | ||
83 | (Just(s), edits) | ||
84 | }) | ||
85 | .boxed() | ||
86 | } | ||
87 | |||
88 | fn intersect(r1: TextRange, r2: TextRange) -> Option<TextRange> { | ||
89 | let start = r1.start().max(r2.start()); | ||
90 | let end = r1.end().min(r2.end()); | ||
91 | if start <= end { | ||
92 | Some(TextRange::from_to(start, end)) | ||
93 | } else { | ||
94 | None | ||
95 | } | ||
96 | } | ||
97 | proptest! { | ||
98 | #[test] | ||
99 | fn atom_text_edits_are_valid((text, edits) in arb_text_with_edits()) { | ||
100 | proptest_atom_text_edits_are_valid(text, edits) | ||
101 | } | ||
102 | } | ||
103 | 76 | ||
104 | fn proptest_atom_text_edits_are_valid(text: String, edits: Vec<AtomTextEdit>) { | 77 | pub fn arb_text_with_edits() -> BoxedStrategy<ArbTextWithEdits> { |
105 | // slicing doesn't panic | 78 | let text = arb_text(); |
106 | for e in &edits { | 79 | text.prop_flat_map(|s| { |
107 | let _ = &text[e.delete]; | 80 | let edits = arb_text_edit(&s); |
108 | } | 81 | (Just(s), edits) |
109 | // ranges do not overlap | 82 | }) |
110 | for i in 1..edits.len() { | 83 | .prop_map(|(text, edits)| ArbTextWithEdits { text, edits }) |
111 | let e1 = &edits[i]; | 84 | .boxed() |
112 | for e2 in &edits[0..i] { | ||
113 | if intersect(e1.delete, e2.delete).is_some() { | ||
114 | assert!(false, "Overlapping ranges {} {}", e1.delete, e2.delete); | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | } | 85 | } |
diff --git a/crates/ra_text_edit/src/text_edit.rs b/crates/ra_text_edit/src/text_edit.rs index 392968d63..0881f3e1c 100644 --- a/crates/ra_text_edit/src/text_edit.rs +++ b/crates/ra_text_edit/src/text_edit.rs | |||
@@ -26,12 +26,7 @@ impl TextEditBuilder { | |||
26 | self.atoms.push(AtomTextEdit::insert(offset, text)) | 26 | self.atoms.push(AtomTextEdit::insert(offset, text)) |
27 | } | 27 | } |
28 | pub fn finish(self) -> TextEdit { | 28 | pub fn finish(self) -> TextEdit { |
29 | let mut atoms = self.atoms; | 29 | TextEdit::from_atoms(self.atoms) |
30 | atoms.sort_by_key(|a| (a.delete.start(), a.delete.end())); | ||
31 | for (a1, a2) in atoms.iter().zip(atoms.iter().skip(1)) { | ||
32 | assert!(a1.delete.end() <= a2.delete.start()) | ||
33 | } | ||
34 | TextEdit { atoms } | ||
35 | } | 30 | } |
36 | pub fn invalidates_offset(&self, offset: TextUnit) -> bool { | 31 | pub fn invalidates_offset(&self, offset: TextUnit) -> bool { |
37 | self.atoms | 32 | self.atoms |
@@ -41,6 +36,14 @@ impl TextEditBuilder { | |||
41 | } | 36 | } |
42 | 37 | ||
43 | impl TextEdit { | 38 | impl TextEdit { |
39 | pub(crate) fn from_atoms(mut atoms: Vec<AtomTextEdit>) -> TextEdit { | ||
40 | atoms.sort_by_key(|a| (a.delete.start(), a.delete.end())); | ||
41 | for (a1, a2) in atoms.iter().zip(atoms.iter().skip(1)) { | ||
42 | assert!(a1.delete.end() <= a2.delete.start()) | ||
43 | } | ||
44 | TextEdit { atoms } | ||
45 | } | ||
46 | |||
44 | pub fn as_atoms(&self) -> &[AtomTextEdit] { | 47 | pub fn as_atoms(&self) -> &[AtomTextEdit] { |
45 | &self.atoms | 48 | &self.atoms |
46 | } | 49 | } |