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

MitMaro / git-interactive-rebase-tool / 14537971056

18 Apr 2025 04:04PM UTC coverage: 97.236% (-0.1%) from 97.339%
14537971056

Pull #959

github

web-flow
Merge c6e297710 into d407c14ab
Pull Request #959: WIP: Move Diff to Thread

459 of 489 new or added lines in 33 files covered. (93.87%)

4 existing lines in 2 files now uncovered.

4819 of 4956 relevant lines covered (97.24%)

2.74 hits per line

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

88.89
/src/diff/thread.rs
1
mod action;
2
mod load_status;
3
mod state;
4
mod update_handler;
5

6
use std::sync::Arc;
7

8
use captur::capture;
9
use parking_lot::Mutex;
10

11
pub(crate) use self::{action::Action, load_status::LoadStatus, state::State, update_handler::UpdateHandlerFn};
12
use crate::{
13
        diff::CommitDiffLoader,
14
        runtime::{Installer, Threadable},
15
};
16

17
pub(crate) const THREAD_NAME: &str = "diff";
18

19
#[derive(Debug)]
20
pub(crate) struct Thread<UpdateHandler: UpdateHandlerFn> {
21
        state: State,
22
        commit_diff_loader: Arc<Mutex<CommitDiffLoader>>,
23
        update_handler: Arc<UpdateHandler>,
24
}
25

26
impl<UpdateHandler> Threadable for Thread<UpdateHandler>
27
where UpdateHandler: UpdateHandlerFn + 'static
28
{
29
        fn install(&self, installer: &Installer) {
4✔
30
                let state = self.state();
4✔
31

32
                installer.spawn(THREAD_NAME, |notifier| {
8✔
33
                        let update_handler = Arc::clone(&self.update_handler);
8✔
34
                        let commit_diff_loader = Arc::clone(&self.commit_diff_loader);
8✔
35
                        move || {
8✔
36
                                capture!(notifier, state);
4✔
37

38
                                notifier.wait();
8✔
39

40
                                loop {
3✔
41
                                        notifier.wait();
4✔
42
                                        if state.is_ended() {
4✔
NEW
43
                                                break;
×
44
                                        }
45

46
                                        if state.is_cancelled() {
6✔
47
                                                commit_diff_loader.lock().reset();
1✔
48
                                        }
49

50
                                        let msg = state.receive_update();
6✔
51
                                        notifier.busy();
3✔
52
                                        match msg {
3✔
53
                                                Action::Load(hash) => {
1✔
54
                                                        state.resume();
1✔
55
                                                        let mut loader = commit_diff_loader.lock();
1✔
56
                                                        if let Err(e) = loader.load_diff(hash.as_str(), |s: LoadStatus| {
3✔
NEW
57
                                                                state.set_load_status(s);
×
NEW
58
                                                                update_handler();
×
NEW
59
                                                                state.is_cancelled()
×
60
                                                        }) {
61
                                                                state.set_load_status(LoadStatus::Error {
2✔
62
                                                                        msg: e.to_string(),
1✔
63
                                                                        code: e.code(),
1✔
64
                                                                });
65
                                                                state.cancel();
1✔
66
                                                                update_handler();
1✔
67
                                                                // TODO what to do here with the diff?
68
                                                        }
69
                                                },
NEW
70
                                                Action::StatusChange => {},
×
71
                                        }
72
                                }
73

74
                                notifier.request_end();
4✔
75
                                notifier.end();
4✔
76
                        }
77
                });
78
        }
79

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

84
        fn resume(&self) {
1✔
85
                self.state.resume();
1✔
86
        }
87

88
        fn end(&self) {
1✔
89
                self.state.end();
1✔
90
        }
91
}
92

93
impl<UpdateHandler> Thread<UpdateHandler>
94
where UpdateHandler: UpdateHandlerFn
95
{
96
        pub(crate) fn new(commit_diff_loader: CommitDiffLoader, update_handler: UpdateHandler) -> Self {
4✔
97
                let commit_diff = commit_diff_loader.commit_diff();
8✔
98
                Self {
99
                        state: State::new(commit_diff),
4✔
100
                        commit_diff_loader: Arc::new(Mutex::new(commit_diff_loader)),
8✔
101
                        update_handler: Arc::new(update_handler),
4✔
102
                }
103
        }
104

105
        pub(crate) fn state(&self) -> State {
4✔
106
                self.state.clone()
4✔
107
        }
108
}
109

110
#[cfg(test)]
111
mod tests {
112
        use std::{thread::sleep, time::Duration};
113

114
        use super::*;
115
        use crate::{
116
                diff::CommitDiffLoaderOptions,
117
                runtime::Status,
118
                test_helpers::{testers, with_temp_repository},
119
        };
120

121
        #[test]
122
        fn set_pause_resume() {
123
                with_temp_repository(|repository| {
124
                        let diff_loader = CommitDiffLoader::new(repository, CommitDiffLoaderOptions::new());
125
                        let diff = diff_loader.commit_diff();
126
                        diff.write().update(vec![], 1, 2, 3);
127
                        let thread = Thread::new(diff_loader, || {});
128

129
                        let state = thread.state();
130
                        let tester = testers::Threadable::new();
131
                        tester.start_threadable(&thread, THREAD_NAME);
132
                        tester.wait_for_status(&Status::Waiting);
133
                        thread.pause();
134
                        assert!(state.is_cancelled());
135
                        let mut pass = false;
136
                        for _ in 0..10 {
137
                                if diff.read().number_deletions() == 0 {
138
                                        pass = true;
139
                                        break;
140
                                }
141
                                sleep(Duration::from_millis(10));
142
                        }
143
                        assert!(pass);
144
                        thread.resume();
145
                        assert!(!state.is_cancelled());
146
                        state.end();
147
                        tester.wait_for_status(&Status::Ended);
148
                });
149
        }
150

151
        #[test]
152
        fn set_end() {
153
                with_temp_repository(|repository| {
154
                        let thread = Thread::new(CommitDiffLoader::new(repository, CommitDiffLoaderOptions::new()), || {});
155

156
                        let state = thread.state();
157
                        let tester = testers::Threadable::new();
158
                        tester.start_threadable(&thread, THREAD_NAME);
159
                        tester.wait_for_status(&Status::Waiting);
160
                        state.end();
161
                        assert!(state.is_ended());
162
                        tester.wait_for_status(&Status::Ended);
163
                });
164
        }
165

166
        #[test]
167
        fn diff_load_error() {
168
                with_temp_repository(|repository| {
169
                        let thread = Thread::new(CommitDiffLoader::new(repository, CommitDiffLoaderOptions::new()), || {});
170

171
                        let state = thread.state();
172
                        let tester = testers::Threadable::new();
173
                        tester.start_threadable(&thread, THREAD_NAME);
174
                        tester.wait_for_status(&Status::Waiting);
175

176
                        state.start_load("abc123");
177

178
                        let mut pass = false;
179
                        for _ in 0..10 {
180
                                if let LoadStatus::Error { .. } = state.load_status() {
181
                                        pass = true;
182
                                        break;
183
                                }
184
                                sleep(Duration::from_millis(10));
185
                        }
186
                        assert!(pass);
187
                        assert!(state.is_cancelled());
188

189
                        state.end();
190
                        tester.wait_for_status(&Status::Ended);
191
                });
192
        }
193
}
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