• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MitMaro / git-interactive-rebase-tool / 14340401715

08 Apr 2025 06:00PM UTC coverage: 95.488% (-1.9%) from 97.339%
14340401715

Pull #959

github

web-flow
Merge 755a26246 into aa2157af9
Pull Request #959: WIP: Move Diff to Thread

372 of 483 new or added lines in 31 files covered. (77.02%)

4 existing lines in 2 files now uncovered.

4741 of 4965 relevant lines covered (95.49%)

2.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

59.09
/src/diff/thread.rs
1
use std::sync::Arc;
2

3
use captur::capture;
4
use parking_lot::Mutex;
5

6
use crate::{
7
        diff::{Action, CommitDiffLoader, State, UpdateHandlerFn, state::LoadStatus},
8
        runtime::{Installer, RuntimeError, Threadable},
9
};
10

11
pub(crate) const THREAD_NAME: &str = "diff";
12

13
#[derive(Debug)]
14
pub(crate) struct Thread<UpdateHandler: UpdateHandlerFn> {
15
        state: State,
16
        commit_diff_loader: Arc<Mutex<CommitDiffLoader>>,
17
        update_handler: Arc<UpdateHandler>,
18
}
19

20
impl<UpdateHandler> Threadable for Thread<UpdateHandler>
21
where UpdateHandler: UpdateHandlerFn + 'static
22
{
23
        fn install(&self, installer: &Installer) {
1✔
24
                let state = self.state();
1✔
25

26
                installer.spawn(THREAD_NAME, |notifier| {
2✔
27
                        let update_handler = Arc::clone(&self.update_handler);
2✔
28
                        let commit_diff_loader = Arc::clone(&self.commit_diff_loader);
2✔
29
                        move || {
2✔
30
                                capture!(notifier, state);
1✔
31

32
                                let load_status = state.load_status();
2✔
33
                                notifier.wait();
2✔
34

NEW
35
                                loop {
×
36
                                        notifier.wait();
1✔
37
                                        if state.is_ended() {
1✔
NEW
38
                                                break;
×
39
                                        }
40

41
                                        if state.is_cancelled() {
2✔
NEW
42
                                                commit_diff_loader.lock().reset();
×
43
                                        }
44

45
                                        let msg = state.receive_update();
2✔
46
                                        notifier.busy();
1✔
47
                                        match msg {
1✔
NEW
48
                                                Action::Load(hash) => {
×
NEW
49
                                                        state.resume();
×
NEW
50
                                                        let mut loader = commit_diff_loader.lock();
×
NEW
51
                                                        if let Err(e) = loader.load_diff(hash.as_str(), |s: LoadStatus| {
×
NEW
52
                                                                let mut ls = load_status.write();
×
NEW
53
                                                                *ls = s;
×
NEW
54
                                                                update_handler();
×
NEW
55
                                                                return state.is_cancelled();
×
56
                                                        }) {
NEW
57
                                                                notifier.error(RuntimeError::ThreadError(e.to_string()));
×
NEW
58
                                                                continue;
×
59
                                                        }
60
                                                },
NEW
61
                                                Action::End => continue,
×
62
                                        }
63
                                }
64

65
                                notifier.request_end();
1✔
66
                                notifier.end();
1✔
67
                        }
68
                });
69
        }
70

NEW
71
        fn pause(&self) {
×
NEW
72
                self.state.cancel();
×
73
        }
74

NEW
75
        fn resume(&self) {
×
NEW
76
                self.state.resume();
×
77
        }
78

79
        fn end(&self) {
1✔
80
                self.state.end();
1✔
81
        }
82
}
83

84
impl<UpdateHandler> Thread<UpdateHandler>
85
where UpdateHandler: UpdateHandlerFn
86
{
87
        pub(crate) fn new(commit_diff_loader: CommitDiffLoader, update_handler: UpdateHandler) -> Self {
1✔
88
                let commit_diff = commit_diff_loader.commit_diff();
2✔
89
                Self {
90
                        state: State::new(commit_diff),
1✔
91
                        commit_diff_loader: Arc::new(Mutex::new(commit_diff_loader)),
2✔
92
                        update_handler: Arc::new(update_handler),
1✔
93
                }
94
        }
95

96
        pub(crate) fn state(&self) -> State {
1✔
97
                self.state.clone()
1✔
98
        }
99
}
100

101
// #[cfg(test)]
102
// mod tests {
103
//         use std::sync::atomic::{AtomicUsize, Ordering};
104
//
105
//         use parking_lot::Mutex;
106
//
107
//         use super::*;
108
//         use crate::{runtime::Status, test_helpers::testers};
109
//
110
//         #[derive(Clone)]
111
//         struct MockedSearchable {
112
//                 calls: Arc<Mutex<Vec<String>>>,
113
//                 search_result: Arc<Mutex<SearchResult>>,
114
//         }
115
//
116
//         impl MockedSearchable {
117
//                 fn new() -> Self {
118
//                         Self {
119
//                                 calls: Arc::new(Mutex::new(vec![])),
120
//                                 search_result: Arc::new(Mutex::new(SearchResult::None)),
121
//                         }
122
//                 }
123
//         }
124
//
125
//         impl Searchable for MockedSearchable {
126
//                 fn reset(&mut self) {
127
//                         self.calls.lock().push(String::from("Reset"));
128
//                 }
129
//
130
//                 fn search(&mut self, _: Interrupter, term: &str) -> SearchResult {
131
//                         self.calls.lock().push(format!("Search({term})"));
132
//                         *self.search_result.lock()
133
//                 }
134
//         }
135
//
136
//         #[test]
137
//         fn set_pause_resume() {
138
//                 let thread = Thread::new(|| {});
139
//                 let state = thread.state();
140
//                 let tester = testers::Threadable::new();
141
//                 tester.start_threadable(&thread, THREAD_NAME);
142
//                 tester.wait_for_status(&Status::Waiting);
143
//                 thread.pause();
144
//                 assert!(state.is_paused());
145
//                 // give thread time to pause
146
//                 sleep(Duration::from_secs(1));
147
//                 state.send_update(Action::Continue);
148
//                 thread.resume();
149
//                 assert!(!state.is_paused());
150
//                 state.end();
151
//                 tester.wait_for_status(&Status::Ended);
152
//         }
153
//
154
//         #[test]
155
//         fn set_end() {
156
//                 let thread = Thread::new(|| {});
157
//                 let state = thread.state();
158
//                 thread.end();
159
//                 assert!(state.is_ended());
160
//         }
161
//
162
//         #[test]
163
//         fn thread_end_from_state() {
164
//                 let thread = Thread::new(|| {});
165
//                 let state = thread.state();
166
//
167
//                 let tester = testers::Threadable::new();
168
//                 tester.start_threadable(&thread, THREAD_NAME);
169
//                 tester.wait_for_status(&Status::Waiting);
170
//                 state.end();
171
//                 tester.wait_for_status(&Status::Ended);
172
//         }
173
//
174
//         #[test]
175
//         fn thread_end_from_action() {
176
//                 let thread = Thread::new(|| {});
177
//                 let state = thread.state();
178
//
179
//                 let tester = testers::Threadable::new();
180
//                 tester.start_threadable(&thread, THREAD_NAME);
181
//                 tester.wait_for_status(&Status::Waiting);
182
//                 state.send_update(Action::End);
183
//                 tester.wait_for_status(&Status::Ended);
184
//         }
185
//
186
//         #[test]
187
//         fn thread_start_search() {
188
//                 let update_handler_calls = Arc::new(AtomicUsize::new(0));
189
//                 let update_handler_calls_thread = Arc::clone(&update_handler_calls);
190
//                 let thread = Thread::new(move || {
191
//                         _ = update_handler_calls_thread.fetch_add(1, Ordering::Release);
192
//                 });
193
//                 let state = thread.state();
194
//
195
//                 let searchable = MockedSearchable::new();
196
//
197
//                 let tester = testers::Threadable::new();
198
//                 tester.start_threadable(&thread, THREAD_NAME);
199
//                 tester.wait_for_status(&Status::Waiting);
200
//                 state.send_update(Action::SetSearchable(Box::new(searchable.clone())));
201
//                 state.send_update(Action::Start(String::from("foo")));
202
//                 state.send_update(Action::End);
203
//                 tester.wait_for_status(&Status::Ended);
204
//
205
//                 assert_eq!(update_handler_calls.load(Ordering::Acquire), 1);
206
//                 let calls = searchable.calls.lock();
207
//                 assert_eq!(*calls, vec![String::from("Search(foo)")]);
208
//         }
209
//
210
//         #[test]
211
//         fn thread_start_cancel() {
212
//                 let update_handler_calls = Arc::new(AtomicUsize::new(0));
213
//                 let update_handler_calls_thread = Arc::clone(&update_handler_calls);
214
//                 let thread = Thread::new(move || {
215
//                         _ = update_handler_calls_thread.fetch_add(1, Ordering::Release);
216
//                 });
217
//                 let state = thread.state();
218
//
219
//                 let searchable = MockedSearchable::new();
220
//
221
//                 let tester = testers::Threadable::new();
222
//                 tester.start_threadable(&thread, THREAD_NAME);
223
//                 state.send_update(Action::SetSearchable(Box::new(searchable.clone())));
224
//                 state.send_update(Action::Start(String::from("foo")));
225
//                 state.send_update(Action::Cancel);
226
//                 state.send_update(Action::End);
227
//                 tester.wait_for_status(&Status::Ended);
228
//
229
//                 assert_eq!(update_handler_calls.load(Ordering::Relaxed), 1);
230
//                 let calls = searchable.calls.lock();
231
//                 assert_eq!(*calls, vec![String::from("Search(foo)"), String::from("Reset")]);
232
//         }
233
//
234
//         #[test]
235
//         fn thread_start_continue() {
236
//                 let update_handler_calls = Arc::new(AtomicUsize::new(0));
237
//                 let update_handler_calls_thread = Arc::clone(&update_handler_calls);
238
//                 let thread = Thread::new(move || {
239
//                         _ = update_handler_calls_thread.fetch_add(1, Ordering::Release);
240
//                 });
241
//                 let state = thread.state();
242
//
243
//                 let searchable = MockedSearchable::new();
244
//                 let tester = testers::Threadable::new();
245
//                 tester.start_threadable(&thread, THREAD_NAME);
246
//
247
//                 state.send_update(Action::SetSearchable(Box::new(searchable.clone())));
248
//                 state.send_update(Action::Start(String::from("foo")));
249
//                 state.send_update(Action::Continue);
250
//                 state.send_update(Action::End);
251
//                 tester.wait_for_status(&Status::Ended);
252
//
253
//                 assert_eq!(update_handler_calls.load(Ordering::Acquire), 2);
254
//                 let calls = searchable.calls.lock();
255
//                 assert_eq!(*calls, vec![String::from("Search(foo)"), String::from("Search(foo)")]);
256
//         }
257
//
258
//         #[test]
259
//         fn thread_no_updates_after_complete() {
260
//                 let update_handler_calls = Arc::new(AtomicUsize::new(0));
261
//                 let update_handler_calls_thread = Arc::clone(&update_handler_calls);
262
//                 let thread = Thread::new(move || {
263
//                         _ = update_handler_calls_thread.fetch_add(1, Ordering::Release);
264
//                 });
265
//                 let state = thread.state();
266
//
267
//                 let searchable = MockedSearchable::new();
268
//                 let tester = testers::Threadable::new();
269
//                 tester.start_threadable(&thread, THREAD_NAME);
270
//
271
//                 state.send_update(Action::SetSearchable(Box::new(searchable.clone())));
272
//                 state.send_update(Action::Start(String::from("foo")));
273
//                 *searchable.search_result.lock() = SearchResult::Complete;
274
//                 state.send_update(Action::Continue);
275
//                 state.send_update(Action::End);
276
//                 tester.wait_for_status(&Status::Ended);
277
//
278
//                 assert_eq!(update_handler_calls.load(Ordering::Acquire), 1);
279
//                 let calls = searchable.calls.lock();
280
//                 assert_eq!(*calls, vec![String::from("Search(foo)")]);
281
//         }
282
//
283
//         #[test]
284
//         fn thread_no_updates_on_empty_term() {
285
//                 let update_handler_calls = Arc::new(AtomicUsize::new(0));
286
//                 let update_handler_calls_thread = Arc::clone(&update_handler_calls);
287
//                 let thread = Thread::new(move || {
288
//                         _ = update_handler_calls_thread.fetch_add(1, Ordering::Release);
289
//                 });
290
//                 let state = thread.state();
291
//
292
//                 let searchable = MockedSearchable::new();
293
//                 let tester = testers::Threadable::new();
294
//                 tester.start_threadable(&thread, THREAD_NAME);
295
//
296
//                 state.send_update(Action::SetSearchable(Box::new(searchable.clone())));
297
//                 state.send_update(Action::Start(String::new()));
298
//                 state.send_update(Action::End);
299
//                 tester.wait_for_status(&Status::Ended);
300
//
301
//                 assert_eq!(update_handler_calls.load(Ordering::Acquire), 0);
302
//                 let calls = searchable.calls.lock();
303
//                 assert!(calls.is_empty());
304
//         }
305
//
306
//         #[test]
307
//         fn thread_no_additional_updates_on_start_with_same_term() {
308
//                 let update_handler_calls = Arc::new(AtomicUsize::new(0));
309
//                 let update_handler_calls_thread = Arc::clone(&update_handler_calls);
310
//                 let thread = Thread::new(move || {
311
//                         _ = update_handler_calls_thread.fetch_add(1, Ordering::Release);
312
//                 });
313
//                 let state = thread.state();
314
//
315
//                 let searchable = MockedSearchable::new();
316
//                 let tester = testers::Threadable::new();
317
//                 tester.start_threadable(&thread, THREAD_NAME);
318
//
319
//                 state.send_update(Action::SetSearchable(Box::new(searchable.clone())));
320
//                 state.send_update(Action::Start(String::from("foo")));
321
//                 state.send_update(Action::Start(String::from("foo")));
322
//                 state.send_update(Action::End);
323
//                 tester.wait_for_status(&Status::Ended);
324
//
325
//                 assert_eq!(update_handler_calls.load(Ordering::Acquire), 1);
326
//                 let calls = searchable.calls.lock();
327
//                 assert_eq!(*calls, vec![String::from("Search(foo)")]);
328
//         }
329
//
330
//         #[test]
331
//         fn thread_no_updates_on_no_searchable() {
332
//                 let update_handler_calls = Arc::new(AtomicUsize::new(0));
333
//                 let update_handler_calls_thread = Arc::clone(&update_handler_calls);
334
//                 let thread = Thread::new(move || {
335
//                         _ = update_handler_calls_thread.fetch_add(1, Ordering::Release);
336
//                 });
337
//                 let state = thread.state();
338
//
339
//                 let tester = testers::Threadable::new();
340
//                 tester.start_threadable(&thread, THREAD_NAME);
341
//
342
//                 state.send_update(Action::Start(String::from("foo")));
343
//                 state.send_update(Action::End);
344
//                 tester.wait_for_status(&Status::Ended);
345
//
346
//                 assert_eq!(update_handler_calls.load(Ordering::Acquire), 0);
347
//         }
348
//
349
//         #[test]
350
//         fn thread_updates_after_timeout() {
351
//                 let update_handler_calls = Arc::new(AtomicUsize::new(0));
352
//                 let update_handler_calls_thread = Arc::clone(&update_handler_calls);
353
//                 let thread = Thread::new(move || {
354
//                         _ = update_handler_calls_thread.fetch_add(1, Ordering::Release);
355
//                 });
356
//                 let state = thread.state();
357
//
358
//                 let searchable = MockedSearchable::new();
359
//                 let tester = testers::Threadable::new();
360
//                 tester.start_threadable(&thread, THREAD_NAME);
361
//
362
//                 state.send_update(Action::SetSearchable(Box::new(searchable.clone())));
363
//                 state.send_update(Action::Start(String::from("foo")));
364
//                 sleep(Duration::from_millis(750)); // will timeout after 500ms
365
//                 state.send_update(Action::End);
366
//                 tester.wait_for_status(&Status::Ended);
367
//
368
//                 assert_eq!(update_handler_calls.load(Ordering::Acquire), 2);
369
//                 let calls = searchable.calls.lock();
370
//                 assert_eq!(*calls, vec![String::from("Search(foo)"), String::from("Search(foo)")]);
371
//         }
372
// }
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc