##// END OF EJS Templates
rust: remove use of `EntryState` in `DirsMultiset`...
Raphaël Gomès -
r50028:66e22a4d default
parent child Browse files
Show More
@@ -1,417 +1,418 b''
1 // dirs_multiset.rs
1 // dirs_multiset.rs
2 //
2 //
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 //
4 //
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 //! A multiset of directory names.
8 //! A multiset of directory names.
9 //!
9 //!
10 //! Used to counts the references to directories in a manifest or dirstate.
10 //! Used to counts the references to directories in a manifest or dirstate.
11 use crate::dirstate_tree::on_disk::DirstateV2ParseError;
11 use crate::dirstate_tree::on_disk::DirstateV2ParseError;
12 use crate::{
12 use crate::{
13 dirstate::EntryState,
14 utils::{
13 utils::{
15 files,
14 files,
16 hg_path::{HgPath, HgPathBuf, HgPathError},
15 hg_path::{HgPath, HgPathBuf, HgPathError},
17 },
16 },
18 DirstateEntry, DirstateError, DirstateMapError, FastHashMap,
17 DirstateEntry, DirstateError, DirstateMapError, FastHashMap,
19 };
18 };
20 use std::collections::{hash_map, hash_map::Entry, HashMap, HashSet};
19 use std::collections::{hash_map, hash_map::Entry, HashMap, HashSet};
21
20
22 // could be encapsulated if we care API stability more seriously
21 // could be encapsulated if we care API stability more seriously
23 pub type DirsMultisetIter<'a> = hash_map::Keys<'a, HgPathBuf, u32>;
22 pub type DirsMultisetIter<'a> = hash_map::Keys<'a, HgPathBuf, u32>;
24
23
25 #[derive(PartialEq, Debug)]
24 #[derive(PartialEq, Debug)]
26 pub struct DirsMultiset {
25 pub struct DirsMultiset {
27 inner: FastHashMap<HgPathBuf, u32>,
26 inner: FastHashMap<HgPathBuf, u32>,
28 }
27 }
29
28
30 impl DirsMultiset {
29 impl DirsMultiset {
31 /// Initializes the multiset from a dirstate.
30 /// Initializes the multiset from a dirstate.
32 ///
31 ///
33 /// If `skip_state` is provided, skips dirstate entries with equal state.
32 /// If `skip_state` is provided, skips dirstate entries with equal state.
34 pub fn from_dirstate<I, P>(
33 pub fn from_dirstate<I, P>(
35 dirstate: I,
34 dirstate: I,
36 only_tracked: bool,
35 only_tracked: bool,
37 ) -> Result<Self, DirstateError>
36 ) -> Result<Self, DirstateError>
38 where
37 where
39 I: IntoIterator<
38 I: IntoIterator<
40 Item = Result<(P, DirstateEntry), DirstateV2ParseError>,
39 Item = Result<(P, DirstateEntry), DirstateV2ParseError>,
41 >,
40 >,
42 P: AsRef<HgPath>,
41 P: AsRef<HgPath>,
43 {
42 {
44 let mut multiset = DirsMultiset {
43 let mut multiset = DirsMultiset {
45 inner: FastHashMap::default(),
44 inner: FastHashMap::default(),
46 };
45 };
47 for item in dirstate {
46 for item in dirstate {
48 let (filename, entry) = item?;
47 let (filename, entry) = item?;
49 let filename = filename.as_ref();
48 let filename = filename.as_ref();
50 // This `if` is optimized out of the loop
49 // This `if` is optimized out of the loop
51 if only_tracked {
50 if only_tracked {
52 if entry.state() != EntryState::Removed {
51 if !entry.removed() {
53 multiset.add_path(filename)?;
52 multiset.add_path(filename)?;
54 }
53 }
55 } else {
54 } else {
56 multiset.add_path(filename)?;
55 multiset.add_path(filename)?;
57 }
56 }
58 }
57 }
59
58
60 Ok(multiset)
59 Ok(multiset)
61 }
60 }
62
61
63 /// Initializes the multiset from a manifest.
62 /// Initializes the multiset from a manifest.
64 pub fn from_manifest(
63 pub fn from_manifest(
65 manifest: &[impl AsRef<HgPath>],
64 manifest: &[impl AsRef<HgPath>],
66 ) -> Result<Self, DirstateMapError> {
65 ) -> Result<Self, DirstateMapError> {
67 let mut multiset = DirsMultiset {
66 let mut multiset = DirsMultiset {
68 inner: FastHashMap::default(),
67 inner: FastHashMap::default(),
69 };
68 };
70
69
71 for filename in manifest {
70 for filename in manifest {
72 multiset.add_path(filename.as_ref())?;
71 multiset.add_path(filename.as_ref())?;
73 }
72 }
74
73
75 Ok(multiset)
74 Ok(multiset)
76 }
75 }
77
76
78 /// Increases the count of deepest directory contained in the path.
77 /// Increases the count of deepest directory contained in the path.
79 ///
78 ///
80 /// If the directory is not yet in the map, adds its parents.
79 /// If the directory is not yet in the map, adds its parents.
81 pub fn add_path(
80 pub fn add_path(
82 &mut self,
81 &mut self,
83 path: impl AsRef<HgPath>,
82 path: impl AsRef<HgPath>,
84 ) -> Result<(), DirstateMapError> {
83 ) -> Result<(), DirstateMapError> {
85 for subpath in files::find_dirs(path.as_ref()) {
84 for subpath in files::find_dirs(path.as_ref()) {
86 if subpath.as_bytes().last() == Some(&b'/') {
85 if subpath.as_bytes().last() == Some(&b'/') {
87 // TODO Remove this once PathAuditor is certified
86 // TODO Remove this once PathAuditor is certified
88 // as the only entrypoint for path data
87 // as the only entrypoint for path data
89 let second_slash_index = subpath.len() - 1;
88 let second_slash_index = subpath.len() - 1;
90
89
91 return Err(DirstateMapError::InvalidPath(
90 return Err(DirstateMapError::InvalidPath(
92 HgPathError::ConsecutiveSlashes {
91 HgPathError::ConsecutiveSlashes {
93 bytes: path.as_ref().as_bytes().to_owned(),
92 bytes: path.as_ref().as_bytes().to_owned(),
94 second_slash_index,
93 second_slash_index,
95 },
94 },
96 ));
95 ));
97 }
96 }
98 if let Some(val) = self.inner.get_mut(subpath) {
97 if let Some(val) = self.inner.get_mut(subpath) {
99 *val += 1;
98 *val += 1;
100 break;
99 break;
101 }
100 }
102 self.inner.insert(subpath.to_owned(), 1);
101 self.inner.insert(subpath.to_owned(), 1);
103 }
102 }
104 Ok(())
103 Ok(())
105 }
104 }
106
105
107 /// Decreases the count of deepest directory contained in the path.
106 /// Decreases the count of deepest directory contained in the path.
108 ///
107 ///
109 /// If it is the only reference, decreases all parents until one is
108 /// If it is the only reference, decreases all parents until one is
110 /// removed.
109 /// removed.
111 /// If the directory is not in the map, something horrible has happened.
110 /// If the directory is not in the map, something horrible has happened.
112 pub fn delete_path(
111 pub fn delete_path(
113 &mut self,
112 &mut self,
114 path: impl AsRef<HgPath>,
113 path: impl AsRef<HgPath>,
115 ) -> Result<(), DirstateMapError> {
114 ) -> Result<(), DirstateMapError> {
116 for subpath in files::find_dirs(path.as_ref()) {
115 for subpath in files::find_dirs(path.as_ref()) {
117 match self.inner.entry(subpath.to_owned()) {
116 match self.inner.entry(subpath.to_owned()) {
118 Entry::Occupied(mut entry) => {
117 Entry::Occupied(mut entry) => {
119 let val = *entry.get();
118 let val = *entry.get();
120 if val > 1 {
119 if val > 1 {
121 entry.insert(val - 1);
120 entry.insert(val - 1);
122 break;
121 break;
123 }
122 }
124 entry.remove();
123 entry.remove();
125 }
124 }
126 Entry::Vacant(_) => {
125 Entry::Vacant(_) => {
127 return Err(DirstateMapError::PathNotFound(
126 return Err(DirstateMapError::PathNotFound(
128 path.as_ref().to_owned(),
127 path.as_ref().to_owned(),
129 ))
128 ))
130 }
129 }
131 };
130 };
132 }
131 }
133
132
134 Ok(())
133 Ok(())
135 }
134 }
136
135
137 pub fn contains(&self, key: impl AsRef<HgPath>) -> bool {
136 pub fn contains(&self, key: impl AsRef<HgPath>) -> bool {
138 self.inner.contains_key(key.as_ref())
137 self.inner.contains_key(key.as_ref())
139 }
138 }
140
139
141 pub fn iter(&self) -> DirsMultisetIter {
140 pub fn iter(&self) -> DirsMultisetIter {
142 self.inner.keys()
141 self.inner.keys()
143 }
142 }
144
143
145 pub fn len(&self) -> usize {
144 pub fn len(&self) -> usize {
146 self.inner.len()
145 self.inner.len()
147 }
146 }
148
147
149 pub fn is_empty(&self) -> bool {
148 pub fn is_empty(&self) -> bool {
150 self.len() == 0
149 self.len() == 0
151 }
150 }
152 }
151 }
153
152
154 /// This is basically a reimplementation of `DirsMultiset` that stores the
153 /// This is basically a reimplementation of `DirsMultiset` that stores the
155 /// children instead of just a count of them, plus a small optional
154 /// children instead of just a count of them, plus a small optional
156 /// optimization to avoid some directories we don't need.
155 /// optimization to avoid some directories we don't need.
157 #[derive(PartialEq, Debug)]
156 #[derive(PartialEq, Debug)]
158 pub struct DirsChildrenMultiset<'a> {
157 pub struct DirsChildrenMultiset<'a> {
159 inner: FastHashMap<&'a HgPath, HashSet<&'a HgPath>>,
158 inner: FastHashMap<&'a HgPath, HashSet<&'a HgPath>>,
160 only_include: Option<HashSet<&'a HgPath>>,
159 only_include: Option<HashSet<&'a HgPath>>,
161 }
160 }
162
161
163 impl<'a> DirsChildrenMultiset<'a> {
162 impl<'a> DirsChildrenMultiset<'a> {
164 pub fn new(
163 pub fn new(
165 paths: impl Iterator<Item = &'a HgPathBuf>,
164 paths: impl Iterator<Item = &'a HgPathBuf>,
166 only_include: Option<&'a HashSet<impl AsRef<HgPath> + 'a>>,
165 only_include: Option<&'a HashSet<impl AsRef<HgPath> + 'a>>,
167 ) -> Self {
166 ) -> Self {
168 let mut new = Self {
167 let mut new = Self {
169 inner: HashMap::default(),
168 inner: HashMap::default(),
170 only_include: only_include
169 only_include: only_include
171 .map(|s| s.iter().map(AsRef::as_ref).collect()),
170 .map(|s| s.iter().map(AsRef::as_ref).collect()),
172 };
171 };
173
172
174 for path in paths {
173 for path in paths {
175 new.add_path(path)
174 new.add_path(path)
176 }
175 }
177
176
178 new
177 new
179 }
178 }
180 fn add_path(&mut self, path: &'a (impl AsRef<HgPath> + 'a)) {
179 fn add_path(&mut self, path: &'a (impl AsRef<HgPath> + 'a)) {
181 if path.as_ref().is_empty() {
180 if path.as_ref().is_empty() {
182 return;
181 return;
183 }
182 }
184 for (directory, basename) in files::find_dirs_with_base(path.as_ref())
183 for (directory, basename) in files::find_dirs_with_base(path.as_ref())
185 {
184 {
186 if !self.is_dir_included(directory) {
185 if !self.is_dir_included(directory) {
187 continue;
186 continue;
188 }
187 }
189 self.inner
188 self.inner
190 .entry(directory)
189 .entry(directory)
191 .and_modify(|e| {
190 .and_modify(|e| {
192 e.insert(basename);
191 e.insert(basename);
193 })
192 })
194 .or_insert_with(|| {
193 .or_insert_with(|| {
195 let mut set = HashSet::new();
194 let mut set = HashSet::new();
196 set.insert(basename);
195 set.insert(basename);
197 set
196 set
198 });
197 });
199 }
198 }
200 }
199 }
201 fn is_dir_included(&self, dir: impl AsRef<HgPath>) -> bool {
200 fn is_dir_included(&self, dir: impl AsRef<HgPath>) -> bool {
202 match &self.only_include {
201 match &self.only_include {
203 None => false,
202 None => false,
204 Some(i) => i.contains(dir.as_ref()),
203 Some(i) => i.contains(dir.as_ref()),
205 }
204 }
206 }
205 }
207
206
208 pub fn get(
207 pub fn get(
209 &self,
208 &self,
210 path: impl AsRef<HgPath>,
209 path: impl AsRef<HgPath>,
211 ) -> Option<&HashSet<&'a HgPath>> {
210 ) -> Option<&HashSet<&'a HgPath>> {
212 self.inner.get(path.as_ref())
211 self.inner.get(path.as_ref())
213 }
212 }
214 }
213 }
215
214
216 #[cfg(test)]
215 #[cfg(test)]
217 mod tests {
216 mod tests {
217 use crate::EntryState;
218
218 use super::*;
219 use super::*;
219
220
220 #[test]
221 #[test]
221 fn test_delete_path_path_not_found() {
222 fn test_delete_path_path_not_found() {
222 let manifest: Vec<HgPathBuf> = vec![];
223 let manifest: Vec<HgPathBuf> = vec![];
223 let mut map = DirsMultiset::from_manifest(&manifest).unwrap();
224 let mut map = DirsMultiset::from_manifest(&manifest).unwrap();
224 let path = HgPathBuf::from_bytes(b"doesnotexist/");
225 let path = HgPathBuf::from_bytes(b"doesnotexist/");
225 assert_eq!(
226 assert_eq!(
226 Err(DirstateMapError::PathNotFound(path.to_owned())),
227 Err(DirstateMapError::PathNotFound(path.to_owned())),
227 map.delete_path(&path)
228 map.delete_path(&path)
228 );
229 );
229 }
230 }
230
231
231 #[test]
232 #[test]
232 fn test_delete_path_empty_path() {
233 fn test_delete_path_empty_path() {
233 let mut map =
234 let mut map =
234 DirsMultiset::from_manifest(&vec![HgPathBuf::new()]).unwrap();
235 DirsMultiset::from_manifest(&vec![HgPathBuf::new()]).unwrap();
235 let path = HgPath::new(b"");
236 let path = HgPath::new(b"");
236 assert_eq!(Ok(()), map.delete_path(path));
237 assert_eq!(Ok(()), map.delete_path(path));
237 assert_eq!(
238 assert_eq!(
238 Err(DirstateMapError::PathNotFound(path.to_owned())),
239 Err(DirstateMapError::PathNotFound(path.to_owned())),
239 map.delete_path(path)
240 map.delete_path(path)
240 );
241 );
241 }
242 }
242
243
243 #[test]
244 #[test]
244 fn test_delete_path_successful() {
245 fn test_delete_path_successful() {
245 let mut map = DirsMultiset {
246 let mut map = DirsMultiset {
246 inner: [("", 5), ("a", 3), ("a/b", 2), ("a/c", 1)]
247 inner: [("", 5), ("a", 3), ("a/b", 2), ("a/c", 1)]
247 .iter()
248 .iter()
248 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
249 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
249 .collect(),
250 .collect(),
250 };
251 };
251
252
252 assert_eq!(Ok(()), map.delete_path(HgPath::new(b"a/b/")));
253 assert_eq!(Ok(()), map.delete_path(HgPath::new(b"a/b/")));
253 eprintln!("{:?}", map);
254 eprintln!("{:?}", map);
254 assert_eq!(Ok(()), map.delete_path(HgPath::new(b"a/b/")));
255 assert_eq!(Ok(()), map.delete_path(HgPath::new(b"a/b/")));
255 eprintln!("{:?}", map);
256 eprintln!("{:?}", map);
256 assert_eq!(
257 assert_eq!(
257 Err(DirstateMapError::PathNotFound(HgPathBuf::from_bytes(
258 Err(DirstateMapError::PathNotFound(HgPathBuf::from_bytes(
258 b"a/b/"
259 b"a/b/"
259 ))),
260 ))),
260 map.delete_path(HgPath::new(b"a/b/"))
261 map.delete_path(HgPath::new(b"a/b/"))
261 );
262 );
262
263
263 assert_eq!(2, *map.inner.get(HgPath::new(b"a")).unwrap());
264 assert_eq!(2, *map.inner.get(HgPath::new(b"a")).unwrap());
264 assert_eq!(1, *map.inner.get(HgPath::new(b"a/c")).unwrap());
265 assert_eq!(1, *map.inner.get(HgPath::new(b"a/c")).unwrap());
265 eprintln!("{:?}", map);
266 eprintln!("{:?}", map);
266 assert_eq!(Ok(()), map.delete_path(HgPath::new(b"a/")));
267 assert_eq!(Ok(()), map.delete_path(HgPath::new(b"a/")));
267 eprintln!("{:?}", map);
268 eprintln!("{:?}", map);
268
269
269 assert_eq!(Ok(()), map.delete_path(HgPath::new(b"a/c/")));
270 assert_eq!(Ok(()), map.delete_path(HgPath::new(b"a/c/")));
270 assert_eq!(
271 assert_eq!(
271 Err(DirstateMapError::PathNotFound(HgPathBuf::from_bytes(
272 Err(DirstateMapError::PathNotFound(HgPathBuf::from_bytes(
272 b"a/c/"
273 b"a/c/"
273 ))),
274 ))),
274 map.delete_path(HgPath::new(b"a/c/"))
275 map.delete_path(HgPath::new(b"a/c/"))
275 );
276 );
276 }
277 }
277
278
278 #[test]
279 #[test]
279 fn test_add_path_empty_path() {
280 fn test_add_path_empty_path() {
280 let manifest: Vec<HgPathBuf> = vec![];
281 let manifest: Vec<HgPathBuf> = vec![];
281 let mut map = DirsMultiset::from_manifest(&manifest).unwrap();
282 let mut map = DirsMultiset::from_manifest(&manifest).unwrap();
282 let path = HgPath::new(b"");
283 let path = HgPath::new(b"");
283 map.add_path(path).unwrap();
284 map.add_path(path).unwrap();
284
285
285 assert_eq!(1, map.len());
286 assert_eq!(1, map.len());
286 }
287 }
287
288
288 #[test]
289 #[test]
289 fn test_add_path_successful() {
290 fn test_add_path_successful() {
290 let manifest: Vec<HgPathBuf> = vec![];
291 let manifest: Vec<HgPathBuf> = vec![];
291 let mut map = DirsMultiset::from_manifest(&manifest).unwrap();
292 let mut map = DirsMultiset::from_manifest(&manifest).unwrap();
292
293
293 map.add_path(HgPath::new(b"a/")).unwrap();
294 map.add_path(HgPath::new(b"a/")).unwrap();
294 assert_eq!(1, *map.inner.get(HgPath::new(b"a")).unwrap());
295 assert_eq!(1, *map.inner.get(HgPath::new(b"a")).unwrap());
295 assert_eq!(1, *map.inner.get(HgPath::new(b"")).unwrap());
296 assert_eq!(1, *map.inner.get(HgPath::new(b"")).unwrap());
296 assert_eq!(2, map.len());
297 assert_eq!(2, map.len());
297
298
298 // Non directory should be ignored
299 // Non directory should be ignored
299 map.add_path(HgPath::new(b"a")).unwrap();
300 map.add_path(HgPath::new(b"a")).unwrap();
300 assert_eq!(1, *map.inner.get(HgPath::new(b"a")).unwrap());
301 assert_eq!(1, *map.inner.get(HgPath::new(b"a")).unwrap());
301 assert_eq!(2, map.len());
302 assert_eq!(2, map.len());
302
303
303 // Non directory will still add its base
304 // Non directory will still add its base
304 map.add_path(HgPath::new(b"a/b")).unwrap();
305 map.add_path(HgPath::new(b"a/b")).unwrap();
305 assert_eq!(2, *map.inner.get(HgPath::new(b"a")).unwrap());
306 assert_eq!(2, *map.inner.get(HgPath::new(b"a")).unwrap());
306 assert_eq!(2, map.len());
307 assert_eq!(2, map.len());
307
308
308 // Duplicate path works
309 // Duplicate path works
309 map.add_path(HgPath::new(b"a/")).unwrap();
310 map.add_path(HgPath::new(b"a/")).unwrap();
310 assert_eq!(3, *map.inner.get(HgPath::new(b"a")).unwrap());
311 assert_eq!(3, *map.inner.get(HgPath::new(b"a")).unwrap());
311
312
312 // Nested dir adds to its base
313 // Nested dir adds to its base
313 map.add_path(HgPath::new(b"a/b/")).unwrap();
314 map.add_path(HgPath::new(b"a/b/")).unwrap();
314 assert_eq!(4, *map.inner.get(HgPath::new(b"a")).unwrap());
315 assert_eq!(4, *map.inner.get(HgPath::new(b"a")).unwrap());
315 assert_eq!(1, *map.inner.get(HgPath::new(b"a/b")).unwrap());
316 assert_eq!(1, *map.inner.get(HgPath::new(b"a/b")).unwrap());
316
317
317 // but not its base's base, because it already existed
318 // but not its base's base, because it already existed
318 map.add_path(HgPath::new(b"a/b/c/")).unwrap();
319 map.add_path(HgPath::new(b"a/b/c/")).unwrap();
319 assert_eq!(4, *map.inner.get(HgPath::new(b"a")).unwrap());
320 assert_eq!(4, *map.inner.get(HgPath::new(b"a")).unwrap());
320 assert_eq!(2, *map.inner.get(HgPath::new(b"a/b")).unwrap());
321 assert_eq!(2, *map.inner.get(HgPath::new(b"a/b")).unwrap());
321
322
322 map.add_path(HgPath::new(b"a/c/")).unwrap();
323 map.add_path(HgPath::new(b"a/c/")).unwrap();
323 assert_eq!(1, *map.inner.get(HgPath::new(b"a/c")).unwrap());
324 assert_eq!(1, *map.inner.get(HgPath::new(b"a/c")).unwrap());
324
325
325 let expected = DirsMultiset {
326 let expected = DirsMultiset {
326 inner: [("", 2), ("a", 5), ("a/b", 2), ("a/b/c", 1), ("a/c", 1)]
327 inner: [("", 2), ("a", 5), ("a/b", 2), ("a/b/c", 1), ("a/c", 1)]
327 .iter()
328 .iter()
328 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
329 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
329 .collect(),
330 .collect(),
330 };
331 };
331 assert_eq!(map, expected);
332 assert_eq!(map, expected);
332 }
333 }
333
334
334 #[test]
335 #[test]
335 fn test_dirsmultiset_new_empty() {
336 fn test_dirsmultiset_new_empty() {
336 let manifest: Vec<HgPathBuf> = vec![];
337 let manifest: Vec<HgPathBuf> = vec![];
337 let new = DirsMultiset::from_manifest(&manifest).unwrap();
338 let new = DirsMultiset::from_manifest(&manifest).unwrap();
338 let expected = DirsMultiset {
339 let expected = DirsMultiset {
339 inner: FastHashMap::default(),
340 inner: FastHashMap::default(),
340 };
341 };
341 assert_eq!(expected, new);
342 assert_eq!(expected, new);
342
343
343 let new = DirsMultiset::from_dirstate::<_, HgPathBuf>(
344 let new = DirsMultiset::from_dirstate::<_, HgPathBuf>(
344 std::iter::empty(),
345 std::iter::empty(),
345 false,
346 false,
346 )
347 )
347 .unwrap();
348 .unwrap();
348 let expected = DirsMultiset {
349 let expected = DirsMultiset {
349 inner: FastHashMap::default(),
350 inner: FastHashMap::default(),
350 };
351 };
351 assert_eq!(expected, new);
352 assert_eq!(expected, new);
352 }
353 }
353
354
354 #[test]
355 #[test]
355 fn test_dirsmultiset_new_no_skip() {
356 fn test_dirsmultiset_new_no_skip() {
356 let input_vec: Vec<HgPathBuf> = ["a/", "b/", "a/c", "a/d/"]
357 let input_vec: Vec<HgPathBuf> = ["a/", "b/", "a/c", "a/d/"]
357 .iter()
358 .iter()
358 .map(|e| HgPathBuf::from_bytes(e.as_bytes()))
359 .map(|e| HgPathBuf::from_bytes(e.as_bytes()))
359 .collect();
360 .collect();
360 let expected_inner = [("", 2), ("a", 3), ("b", 1), ("a/d", 1)]
361 let expected_inner = [("", 2), ("a", 3), ("b", 1), ("a/d", 1)]
361 .iter()
362 .iter()
362 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
363 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
363 .collect();
364 .collect();
364
365
365 let new = DirsMultiset::from_manifest(&input_vec).unwrap();
366 let new = DirsMultiset::from_manifest(&input_vec).unwrap();
366 let expected = DirsMultiset {
367 let expected = DirsMultiset {
367 inner: expected_inner,
368 inner: expected_inner,
368 };
369 };
369 assert_eq!(expected, new);
370 assert_eq!(expected, new);
370
371
371 let input_map = ["b/x", "a/c", "a/d/x"].iter().map(|f| {
372 let input_map = ["b/x", "a/c", "a/d/x"].iter().map(|f| {
372 Ok((
373 Ok((
373 HgPathBuf::from_bytes(f.as_bytes()),
374 HgPathBuf::from_bytes(f.as_bytes()),
374 DirstateEntry::from_v1_data(EntryState::Normal, 0, 0, 0),
375 DirstateEntry::from_v1_data(EntryState::Normal, 0, 0, 0),
375 ))
376 ))
376 });
377 });
377 let expected_inner = [("", 2), ("a", 2), ("b", 1), ("a/d", 1)]
378 let expected_inner = [("", 2), ("a", 2), ("b", 1), ("a/d", 1)]
378 .iter()
379 .iter()
379 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
380 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
380 .collect();
381 .collect();
381
382
382 let new = DirsMultiset::from_dirstate(input_map, false).unwrap();
383 let new = DirsMultiset::from_dirstate(input_map, false).unwrap();
383 let expected = DirsMultiset {
384 let expected = DirsMultiset {
384 inner: expected_inner,
385 inner: expected_inner,
385 };
386 };
386 assert_eq!(expected, new);
387 assert_eq!(expected, new);
387 }
388 }
388
389
389 #[test]
390 #[test]
390 fn test_dirsmultiset_new_skip() {
391 fn test_dirsmultiset_new_skip() {
391 let input_map = [
392 let input_map = [
392 ("a/", EntryState::Normal),
393 ("a/", EntryState::Normal),
393 ("a/b", EntryState::Normal),
394 ("a/b", EntryState::Normal),
394 ("a/c", EntryState::Removed),
395 ("a/c", EntryState::Removed),
395 ("a/d", EntryState::Merged),
396 ("a/d", EntryState::Merged),
396 ]
397 ]
397 .iter()
398 .iter()
398 .map(|(f, state)| {
399 .map(|(f, state)| {
399 Ok((
400 Ok((
400 HgPathBuf::from_bytes(f.as_bytes()),
401 HgPathBuf::from_bytes(f.as_bytes()),
401 DirstateEntry::from_v1_data(*state, 0, 0, 0),
402 DirstateEntry::from_v1_data(*state, 0, 0, 0),
402 ))
403 ))
403 });
404 });
404
405
405 // "a" incremented with "a/c" and "a/d/"
406 // "a" incremented with "a/c" and "a/d/"
406 let expected_inner = [("", 1), ("a", 3)]
407 let expected_inner = [("", 1), ("a", 3)]
407 .iter()
408 .iter()
408 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
409 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
409 .collect();
410 .collect();
410
411
411 let new = DirsMultiset::from_dirstate(input_map, true).unwrap();
412 let new = DirsMultiset::from_dirstate(input_map, true).unwrap();
412 let expected = DirsMultiset {
413 let expected = DirsMultiset {
413 inner: expected_inner,
414 inner: expected_inner,
414 };
415 };
415 assert_eq!(expected, new);
416 assert_eq!(expected, new);
416 }
417 }
417 }
418 }
General Comments 0
You need to be logged in to leave comments. Login now