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

Ortham / libloadorder / 13102634600

02 Feb 2025 09:09PM UTC coverage: 92.469% (+0.09%) from 92.381%
13102634600

push

github

Ortham
Set versions and changelogs for 18.2.1

9540 of 10317 relevant lines covered (92.47%)

1559537.96 hits per line

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

99.62
/src/load_order/writable.rs
1
/*
2
 * This file is part of libloadorder
3
 *
4
 * Copyright (C) 2017 Oliver Hamlet
5
 *
6
 * libloadorder is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * libloadorder is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with libloadorder. If not, see <http://www.gnu.org/licenses/>.
18
 */
19
use std::collections::HashSet;
20
use std::fs::create_dir_all;
21
use std::path::Path;
22

23
use unicase::{eq, UniCase};
24

25
use super::mutable::MutableLoadOrder;
26
use super::readable::{ReadableLoadOrder, ReadableLoadOrderBase};
27
use crate::enums::Error;
28
use crate::plugin::Plugin;
29
use crate::GameSettings;
30

31
const MAX_ACTIVE_LIGHT_PLUGINS: usize = 4096;
32
const MAX_ACTIVE_MEDIUM_PLUGINS: usize = 256;
33

34
pub trait WritableLoadOrder: ReadableLoadOrder {
35
    fn game_settings_mut(&mut self) -> &mut GameSettings;
36

37
    fn load(&mut self) -> Result<(), Error>;
38

39
    fn save(&mut self) -> Result<(), Error>;
40

41
    fn add(&mut self, plugin_name: &str) -> Result<usize, Error>;
42

43
    fn remove(&mut self, plugin_name: &str) -> Result<(), Error>;
44

45
    fn set_load_order(&mut self, plugin_names: &[&str]) -> Result<(), Error>;
46

47
    fn set_plugin_index(&mut self, plugin_name: &str, position: usize) -> Result<usize, Error>;
48

49
    fn is_self_consistent(&self) -> Result<bool, Error>;
50

51
    fn is_ambiguous(&self) -> Result<bool, Error>;
52

53
    fn activate(&mut self, plugin_name: &str) -> Result<(), Error>;
54

55
    fn deactivate(&mut self, plugin_name: &str) -> Result<(), Error>;
56

57
    fn set_active_plugins(&mut self, active_plugin_names: &[&str]) -> Result<(), Error>;
58
}
59

60
pub fn add<T: MutableLoadOrder>(load_order: &mut T, plugin_name: &str) -> Result<usize, Error> {
17✔
61
    match load_order.index_of(plugin_name) {
17✔
62
        Some(_) => Err(Error::DuplicatePlugin(plugin_name.to_string())),
1✔
63
        None => {
64
            let plugin = Plugin::new(plugin_name, load_order.game_settings())?;
16✔
65

66
            match load_order.insert_position(&plugin) {
15✔
67
                Some(position) => {
12✔
68
                    load_order.validate_index(&plugin, position)?;
12✔
69
                    load_order.plugins_mut().insert(position, plugin);
11✔
70
                    Ok(position)
11✔
71
                }
72
                None => {
73
                    load_order.validate_index(&plugin, load_order.plugins().len())?;
3✔
74
                    load_order.plugins_mut().push(plugin);
3✔
75
                    Ok(load_order.plugins().len() - 1)
3✔
76
                }
77
            }
78
        }
79
    }
80
}
17✔
81

82
pub fn remove<T: MutableLoadOrder>(load_order: &mut T, plugin_name: &str) -> Result<(), Error> {
5✔
83
    match load_order.index_of(plugin_name) {
5✔
84
        Some(index) => {
4✔
85
            let plugin_path = load_order.game_settings().plugin_path(plugin_name);
4✔
86
            if plugin_path.exists() {
4✔
87
                return Err(Error::InstalledPlugin(plugin_name.to_string()));
1✔
88
            }
3✔
89

3✔
90
            // If this is a master file that depends on a non-master file, it shouldn't be removed
3✔
91
            // without first moving the non-master file later in the load order, unless the next
3✔
92
            // master file also depends on that same non-master file. The non-master file also
3✔
93
            // doesn't need to be moved if this is the last master file in the load order.
3✔
94
            let plugin = &load_order.plugins()[index];
3✔
95
            if plugin.is_master_file() {
3✔
96
                let next_master = &load_order
2✔
97
                    .plugins()
2✔
98
                    .iter()
2✔
99
                    .skip(index + 1)
2✔
100
                    .find(|p| p.is_master_file());
2✔
101

102
                if let Some(next_master) = next_master {
2✔
103
                    let next_master_masters = next_master.masters()?;
2✔
104
                    let next_master_master_names: HashSet<_> =
2✔
105
                        next_master_masters.iter().map(UniCase::new).collect();
2✔
106

107
                    let mut masters = plugin.masters()?;
2✔
108

109
                    // Remove any masters that are also masters of the next master plugin.
110
                    masters.retain(|m| !next_master_master_names.contains(&UniCase::new(m)));
2✔
111

112
                    // Finally, check if any remaining masters are non-master plugins.
113
                    if let Some(n) = masters.iter().find(|n| {
2✔
114
                        load_order
2✔
115
                            .plugins()
2✔
116
                            .iter()
2✔
117
                            .find(|p| p.name_matches(n))
6✔
118
                            .map(|p| !p.is_master_file())
2✔
119
                            // If the master isn't installed, assume it's a master file and so
2✔
120
                            // doesn't prevent removal of the target plugin.
2✔
121
                            .unwrap_or(false)
2✔
122
                    }) {
2✔
123
                        return Err(Error::NonMasterBeforeMaster {
1✔
124
                            master: plugin_name.to_string(),
1✔
125
                            non_master: n.to_string(),
1✔
126
                        });
1✔
127
                    }
1✔
128
                }
×
129
            }
1✔
130

131
            load_order.plugins_mut().remove(index);
2✔
132

2✔
133
            Ok(())
2✔
134
        }
135
        None => Err(Error::PluginNotFound(plugin_name.to_string())),
1✔
136
    }
137
}
5✔
138

139
#[derive(Clone, Copy, Debug, Default)]
140
struct PluginCounts {
141
    light: usize,
142
    medium: usize,
143
    full: usize,
144
}
145

146
impl PluginCounts {
147
    fn count_plugin(&mut self, plugin: &Plugin) {
305,387✔
148
        if plugin.is_light_plugin() {
305,387✔
149
            self.light += 1;
36,869✔
150
        } else if plugin.is_medium_plugin() {
268,518✔
151
            self.medium += 1;
2,311✔
152
        } else {
266,207✔
153
            self.full += 1;
266,207✔
154
        }
266,207✔
155
    }
305,387✔
156
}
157

158
fn count_active_plugins<T: ReadableLoadOrderBase>(load_order: &T) -> PluginCounts {
2,056✔
159
    let mut counts = PluginCounts::default();
2,056✔
160

161
    for plugin in load_order.plugins().iter().filter(|p| p.is_active()) {
567,147✔
162
        counts.count_plugin(plugin);
289,779✔
163
    }
289,779✔
164

165
    counts
2,056✔
166
}
2,056✔
167

168
fn count_plugins(existing_plugins: &[Plugin], existing_plugin_indexes: &[usize]) -> PluginCounts {
15✔
169
    let mut counts = PluginCounts::default();
15✔
170

171
    for index in existing_plugin_indexes {
15,623✔
172
        let plugin = &existing_plugins[*index];
15,608✔
173
        counts.count_plugin(plugin);
15,608✔
174
    }
15,608✔
175

176
    counts
15✔
177
}
15✔
178

179
pub fn activate<T: MutableLoadOrder>(load_order: &mut T, plugin_name: &str) -> Result<(), Error> {
2,056✔
180
    let counts = count_active_plugins(load_order);
2,056✔
181
    let max_active_full_plugins = load_order.max_active_full_plugins();
2,056✔
182

183
    let plugin = match load_order
2,056✔
184
        .plugins_mut()
2,056✔
185
        .iter_mut()
2,056✔
186
        .find(|p| p.name_matches(plugin_name))
273,251✔
187
    {
188
        Some(p) => p,
2,054✔
189
        None => return Err(Error::PluginNotFound(plugin_name.to_string())),
2✔
190
    };
191

192
    if !plugin.is_active() {
2,054✔
193
        let is_light = plugin.is_light_plugin();
2,053✔
194
        let is_medium = plugin.is_medium_plugin();
2,053✔
195
        let is_full = !is_light && !is_medium;
2,053✔
196

197
        if (is_light && counts.light == MAX_ACTIVE_LIGHT_PLUGINS)
2,053✔
198
            || (is_medium && counts.medium == MAX_ACTIVE_MEDIUM_PLUGINS)
2,052✔
199
            || (is_full && counts.full == max_active_full_plugins)
2,051✔
200
        {
201
            return Err(Error::TooManyActivePlugins {
9✔
202
                light_count: counts.light,
9✔
203
                medium_count: counts.medium,
9✔
204
                full_count: counts.full,
9✔
205
            });
9✔
206
        } else {
207
            plugin.activate()?;
2,044✔
208
        }
209
    }
1✔
210

211
    Ok(())
2,045✔
212
}
2,056✔
213

214
pub fn deactivate<T: MutableLoadOrder>(load_order: &mut T, plugin_name: &str) -> Result<(), Error> {
5✔
215
    if load_order.game_settings().is_implicitly_active(plugin_name) {
5✔
216
        return Err(Error::ImplicitlyActivePlugin(plugin_name.to_string()));
2✔
217
    }
3✔
218

3✔
219
    load_order
3✔
220
        .plugins_mut()
3✔
221
        .iter_mut()
3✔
222
        .find(|p| p.name_matches(plugin_name))
5✔
223
        .ok_or_else(|| Error::PluginNotFound(plugin_name.to_string()))
3✔
224
        .map(|p| p.deactivate())
3✔
225
}
5✔
226

227
pub fn set_active_plugins<T: MutableLoadOrder>(
18✔
228
    load_order: &mut T,
18✔
229
    active_plugin_names: &[&str],
18✔
230
) -> Result<(), Error> {
18✔
231
    let existing_plugin_indices = load_order.lookup_plugins(active_plugin_names)?;
18✔
232

233
    let counts = count_plugins(load_order.plugins(), &existing_plugin_indices);
15✔
234

15✔
235
    if counts.full > load_order.max_active_full_plugins()
15✔
236
        || counts.medium > MAX_ACTIVE_MEDIUM_PLUGINS
10✔
237
        || counts.light > MAX_ACTIVE_LIGHT_PLUGINS
9✔
238
    {
239
        return Err(Error::TooManyActivePlugins {
7✔
240
            light_count: counts.light,
7✔
241
            medium_count: counts.medium,
7✔
242
            full_count: counts.full,
7✔
243
        });
7✔
244
    }
8✔
245

246
    for plugin_name in load_order.game_settings().implicitly_active_plugins() {
51✔
247
        // If the plugin isn't installed, don't check that it's in the active
248
        // plugins list. Installed plugins will have already been loaded.
249
        if load_order.index_of(plugin_name).is_some()
51✔
250
            && !active_plugin_names.iter().any(|p| eq(*p, plugin_name))
1✔
251
        {
252
            return Err(Error::ImplicitlyActivePlugin(plugin_name.to_string()));
1✔
253
        }
50✔
254
    }
255

256
    load_order.deactivate_all();
7✔
257

258
    for index in existing_plugin_indices {
9,980✔
259
        load_order.plugins_mut()[index].activate()?;
9,973✔
260
    }
261

262
    Ok(())
7✔
263
}
18✔
264

265
pub fn create_parent_dirs(path: &Path) -> Result<(), Error> {
33✔
266
    if let Some(x) = path.parent() {
33✔
267
        if !x.exists() {
33✔
268
            create_dir_all(x).map_err(|e| Error::IoError(x.to_path_buf(), e))?
14✔
269
        }
19✔
270
    }
×
271
    Ok(())
33✔
272
}
33✔
273

274
#[cfg(test)]
275
mod tests {
276
    use super::*;
277

278
    use std::fs::remove_file;
279
    use std::path::Path;
280

281
    use tempfile::tempdir;
282

283
    use crate::enums::GameId;
284
    use crate::game_settings::GameSettings;
285
    use crate::load_order::mutable::MutableLoadOrder;
286
    use crate::load_order::readable::{ReadableLoadOrder, ReadableLoadOrderBase};
287
    use crate::load_order::tests::{
288
        game_settings_for_test, load_and_insert, mock_game_files, prepare_bulk_full_plugins,
289
        prepare_bulk_plugins, prepend_early_loader, prepend_master, set_blueprint_flag,
290
        set_master_flag,
291
    };
292
    use crate::tests::copy_to_test_dir;
293

294
    struct TestLoadOrder {
295
        game_settings: GameSettings,
296
        plugins: Vec<Plugin>,
297
    }
298

299
    impl ReadableLoadOrderBase for TestLoadOrder {
300
        fn game_settings_base(&self) -> &GameSettings {
62,006✔
301
            &self.game_settings
62,006✔
302
        }
62,006✔
303

304
        fn plugins(&self) -> &[Plugin] {
229,303✔
305
            &self.plugins
229,303✔
306
        }
229,303✔
307
    }
308

309
    impl MutableLoadOrder for TestLoadOrder {
310
        fn plugins_mut(&mut self) -> &mut Vec<Plugin> {
31,229✔
311
            &mut self.plugins
31,229✔
312
        }
31,229✔
313
    }
314

315
    fn prepare(game_id: GameId, game_dir: &Path) -> TestLoadOrder {
43✔
316
        let mut game_settings = game_settings_for_test(game_id, game_dir);
43✔
317
        mock_game_files(&mut game_settings);
43✔
318

43✔
319
        let mut plugins = vec![Plugin::with_active("Blank.esp", &game_settings, true).unwrap()];
43✔
320

43✔
321
        if game_id != GameId::Starfield {
43✔
322
            plugins.push(Plugin::new("Blank - Different.esp", &game_settings).unwrap());
28✔
323
        }
28✔
324

325
        TestLoadOrder {
43✔
326
            game_settings,
43✔
327
            plugins,
43✔
328
        }
43✔
329
    }
43✔
330

331
    fn prepare_bulk_medium_plugins(load_order: &mut TestLoadOrder) -> Vec<String> {
3✔
332
        prepare_bulk_plugins(load_order, "Blank.medium.esm", 260, |i| {
780✔
333
            format!("Blank{}.medium.esm", i)
780✔
334
        })
780✔
335
    }
3✔
336

337
    fn prepare_bulk_light_plugins(load_order: &mut TestLoadOrder) -> Vec<String> {
3✔
338
        prepare_bulk_plugins(load_order, "Blank.small.esm", 5000, |i| {
15,000✔
339
            format!("Blank{}.small.esm", i)
15,000✔
340
        })
15,000✔
341
    }
3✔
342

343
    #[test]
344
    fn add_should_error_if_the_plugin_is_already_in_the_load_order() {
1✔
345
        let tmp_dir = tempdir().unwrap();
1✔
346
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
347

1✔
348
        assert!(add(&mut load_order, "Blank.esm").is_ok());
1✔
349
        assert!(add(&mut load_order, "Blank.esm").is_err());
1✔
350
    }
1✔
351

352
    #[test]
353
    fn add_should_error_if_given_a_master_that_would_hoist_a_non_master() {
1✔
354
        let tmp_dir = tempdir().unwrap();
1✔
355
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
356

1✔
357
        let plugins_dir = &load_order.game_settings().plugins_directory();
1✔
358
        copy_to_test_dir(
1✔
359
            "Blank - Different.esm",
1✔
360
            "Blank - Different.esm",
1✔
361
            load_order.game_settings(),
1✔
362
        );
1✔
363
        set_master_flag(
1✔
364
            GameId::Oblivion,
1✔
365
            &plugins_dir.join("Blank - Different.esm"),
1✔
366
            false,
1✔
367
        )
1✔
368
        .unwrap();
1✔
369
        assert!(add(&mut load_order, "Blank - Different.esm").is_ok());
1✔
370

371
        copy_to_test_dir(
1✔
372
            "Blank - Different Master Dependent.esm",
1✔
373
            "Blank - Different Master Dependent.esm",
1✔
374
            load_order.game_settings(),
1✔
375
        );
1✔
376

1✔
377
        assert!(add(&mut load_order, "Blank - Different Master Dependent.esm").is_err());
1✔
378
    }
1✔
379

380
    #[test]
381
    fn add_should_error_if_the_plugin_is_not_valid() {
1✔
382
        let tmp_dir = tempdir().unwrap();
1✔
383
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
384

1✔
385
        assert!(add(&mut load_order, "invalid.esm").is_err());
1✔
386
    }
1✔
387

388
    #[test]
389
    fn add_should_insert_a_master_before_non_masters() {
1✔
390
        let tmp_dir = tempdir().unwrap();
1✔
391
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
392

1✔
393
        assert!(!load_order.plugins[1].is_master_file());
1✔
394

395
        assert_eq!(0, add(&mut load_order, "Blank.esm").unwrap());
1✔
396
        assert_eq!(0, load_order.index_of("Blank.esm").unwrap());
1✔
397
    }
1✔
398

399
    #[test]
400
    fn add_should_append_a_non_master() {
1✔
401
        let tmp_dir = tempdir().unwrap();
1✔
402
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
403

1✔
404
        assert_eq!(
1✔
405
            2,
1✔
406
            add(&mut load_order, "Blank - Master Dependent.esp").unwrap()
1✔
407
        );
1✔
408
        assert_eq!(
1✔
409
            2,
1✔
410
            load_order.index_of("Blank - Master Dependent.esp").unwrap()
1✔
411
        );
1✔
412
    }
1✔
413

414
    #[test]
415
    fn add_should_hoist_a_non_master_that_a_master_depends_on() {
1✔
416
        let tmp_dir = tempdir().unwrap();
1✔
417
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
418

1✔
419
        let plugins_dir = &load_order.game_settings().plugins_directory();
1✔
420
        copy_to_test_dir(
1✔
421
            "Blank - Different Master Dependent.esm",
1✔
422
            "Blank - Different Master Dependent.esm",
1✔
423
            load_order.game_settings(),
1✔
424
        );
1✔
425
        assert!(add(&mut load_order, "Blank - Different Master Dependent.esm").is_ok());
1✔
426

427
        copy_to_test_dir(
1✔
428
            "Blank - Different.esm",
1✔
429
            "Blank - Different.esm",
1✔
430
            load_order.game_settings(),
1✔
431
        );
1✔
432
        set_master_flag(
1✔
433
            GameId::Oblivion,
1✔
434
            &plugins_dir.join("Blank - Different.esm"),
1✔
435
            false,
1✔
436
        )
1✔
437
        .unwrap();
1✔
438
        assert_eq!(0, add(&mut load_order, "Blank - Different.esm").unwrap());
1✔
439
    }
1✔
440

441
    #[test]
442
    fn add_should_hoist_a_master_that_a_master_depends_on() {
1✔
443
        let tmp_dir = tempdir().unwrap();
1✔
444
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
445

1✔
446
        let plugin_name = "Blank - Master Dependent.esm";
1✔
447
        copy_to_test_dir(plugin_name, plugin_name, load_order.game_settings());
1✔
448
        assert_eq!(0, add(&mut load_order, plugin_name).unwrap());
1✔
449

450
        assert_eq!(0, add(&mut load_order, "Blank.esm").unwrap());
1✔
451
    }
1✔
452

453
    #[test]
454
    fn remove_should_error_if_the_plugin_is_not_in_the_load_order() {
1✔
455
        let tmp_dir = tempdir().unwrap();
1✔
456
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
457
        assert!(remove(&mut load_order, "Blank.esm").is_err());
1✔
458
    }
1✔
459

460
    #[test]
461
    fn remove_should_error_if_the_plugin_is_installed() {
1✔
462
        let tmp_dir = tempdir().unwrap();
1✔
463
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
464
        assert!(remove(&mut load_order, "Blank.esp").is_err());
1✔
465
    }
1✔
466

467
    #[test]
468
    fn remove_should_error_if_removing_a_master_would_leave_a_non_master_it_hoisted_loading_too_early(
1✔
469
    ) {
1✔
470
        let tmp_dir = tempdir().unwrap();
1✔
471
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
472

1✔
473
        prepend_master(&mut load_order);
1✔
474

1✔
475
        let plugin_to_remove = "Blank - Different Master Dependent.esm";
1✔
476

1✔
477
        let plugins_dir = &load_order.game_settings().plugins_directory();
1✔
478
        copy_to_test_dir(
1✔
479
            plugin_to_remove,
1✔
480
            plugin_to_remove,
1✔
481
            load_order.game_settings(),
1✔
482
        );
1✔
483
        assert!(add(&mut load_order, plugin_to_remove).is_ok());
1✔
484

485
        copy_to_test_dir(
1✔
486
            "Blank - Different.esm",
1✔
487
            "Blank - Different.esm",
1✔
488
            load_order.game_settings(),
1✔
489
        );
1✔
490
        set_master_flag(
1✔
491
            GameId::Oblivion,
1✔
492
            &plugins_dir.join("Blank - Different.esm"),
1✔
493
            false,
1✔
494
        )
1✔
495
        .unwrap();
1✔
496
        assert_eq!(1, add(&mut load_order, "Blank - Different.esm").unwrap());
1✔
497

498
        copy_to_test_dir(
1✔
499
            "Blank - Master Dependent.esm",
1✔
500
            "Blank - Master Dependent.esm",
1✔
501
            load_order.game_settings(),
1✔
502
        );
1✔
503
        assert!(add(&mut load_order, "Blank - Master Dependent.esm").is_ok());
1✔
504

505
        let blank_master_dependent = load_order.plugins.remove(1);
1✔
506
        load_order.plugins.insert(3, blank_master_dependent);
1✔
507

1✔
508
        std::fs::remove_file(plugins_dir.join(plugin_to_remove)).unwrap();
1✔
509

1✔
510
        match remove(&mut load_order, plugin_to_remove).unwrap_err() {
1✔
511
            Error::NonMasterBeforeMaster { master, non_master } => {
1✔
512
                assert_eq!("Blank - Different Master Dependent.esm", master);
1✔
513
                assert_eq!("Blank - Different.esm", non_master);
1✔
514
            }
515
            e => panic!("Unexpected error type: {:?}", e),
×
516
        }
517
    }
1✔
518

519
    #[test]
520
    fn remove_should_allow_removal_of_a_master_that_depends_on_a_blueprint_plugin() {
1✔
521
        let tmp_dir = tempdir().unwrap();
1✔
522
        let mut load_order = prepare(GameId::Starfield, tmp_dir.path());
1✔
523

1✔
524
        let plugins_dir = &load_order.game_settings().plugins_directory();
1✔
525

1✔
526
        let plugin_to_remove = "Blank - Override.full.esm";
1✔
527
        copy_to_test_dir(
1✔
528
            plugin_to_remove,
1✔
529
            plugin_to_remove,
1✔
530
            load_order.game_settings(),
1✔
531
        );
1✔
532
        assert!(add(&mut load_order, plugin_to_remove).is_ok());
1✔
533

534
        let blueprint_plugin = "Blank.full.esm";
1✔
535
        copy_to_test_dir(
1✔
536
            blueprint_plugin,
1✔
537
            blueprint_plugin,
1✔
538
            load_order.game_settings(),
1✔
539
        );
1✔
540
        set_blueprint_flag(GameId::Starfield, &plugins_dir.join(blueprint_plugin), true).unwrap();
1✔
541
        assert_eq!(2, add(&mut load_order, blueprint_plugin).unwrap());
1✔
542

543
        let following_master_plugin = "Blank.medium.esm";
1✔
544
        copy_to_test_dir(
1✔
545
            following_master_plugin,
1✔
546
            following_master_plugin,
1✔
547
            load_order.game_settings(),
1✔
548
        );
1✔
549
        assert!(add(&mut load_order, following_master_plugin).is_ok());
1✔
550

551
        std::fs::remove_file(plugins_dir.join(plugin_to_remove)).unwrap();
1✔
552

1✔
553
        assert!(remove(&mut load_order, plugin_to_remove).is_ok());
1✔
554
    }
1✔
555

556
    #[test]
557
    fn remove_should_remove_the_given_plugin_from_the_load_order() {
1✔
558
        let tmp_dir = tempdir().unwrap();
1✔
559
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
560

1✔
561
        remove_file(
1✔
562
            load_order
1✔
563
                .game_settings()
1✔
564
                .plugins_directory()
1✔
565
                .join("Blank.esp"),
1✔
566
        )
1✔
567
        .unwrap();
1✔
568

1✔
569
        assert!(remove(&mut load_order, "Blank.esp").is_ok());
1✔
570
        assert!(load_order.index_of("Blank.esp").is_none());
1✔
571
    }
1✔
572

573
    #[test]
574
    fn activate_should_activate_the_plugin_with_the_given_filename() {
1✔
575
        let tmp_dir = tempdir().unwrap();
1✔
576
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
577

1✔
578
        assert!(activate(&mut load_order, "Blank - Different.esp").is_ok());
1✔
579
        assert!(load_order.is_active("Blank - Different.esp"));
1✔
580
    }
1✔
581

582
    #[test]
583
    fn activate_should_error_if_the_plugin_is_not_valid() {
1✔
584
        let tmp_dir = tempdir().unwrap();
1✔
585
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
586

1✔
587
        assert!(activate(&mut load_order, "missing.esp").is_err());
1✔
588
        assert!(load_order.index_of("missing.esp").is_none());
1✔
589
    }
1✔
590

591
    #[test]
592
    fn activate_should_error_if_the_plugin_is_not_already_in_the_load_order() {
1✔
593
        let tmp_dir = tempdir().unwrap();
1✔
594
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
595

1✔
596
        assert!(activate(&mut load_order, "Blank.esm").is_err());
1✔
597
        assert!(!load_order.is_active("Blank.esm"));
1✔
598
    }
1✔
599

600
    #[test]
601
    fn activate_should_be_case_insensitive() {
1✔
602
        let tmp_dir = tempdir().unwrap();
1✔
603
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
604

1✔
605
        assert!(activate(&mut load_order, "Blank - different.esp").is_ok());
1✔
606
        assert!(load_order.is_active("Blank - Different.esp"));
1✔
607
    }
1✔
608

609
    #[test]
610
    fn activate_should_throw_if_increasing_the_number_of_active_plugins_past_the_limit() {
1✔
611
        let tmp_dir = tempdir().unwrap();
1✔
612
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
613

1✔
614
        let plugins = prepare_bulk_full_plugins(&mut load_order);
1✔
615
        for plugin in &plugins[..254] {
254✔
616
            activate(&mut load_order, plugin).unwrap();
254✔
617
        }
254✔
618

619
        assert!(activate(&mut load_order, "Blank - Different.esp").is_err());
1✔
620
        assert!(!load_order.is_active("Blank - Different.esp"));
1✔
621
    }
1✔
622

623
    #[test]
624
    fn activate_should_succeed_if_at_the_active_plugins_limit_and_the_plugin_is_already_active() {
1✔
625
        let tmp_dir = tempdir().unwrap();
1✔
626
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
627

1✔
628
        let plugins = prepare_bulk_full_plugins(&mut load_order);
1✔
629
        for plugin in &plugins[..254] {
254✔
630
            activate(&mut load_order, plugin).unwrap();
254✔
631
        }
254✔
632

633
        assert!(load_order.is_active("Blank.esp"));
1✔
634
        assert!(activate(&mut load_order, "Blank.esp").is_ok());
1✔
635
    }
1✔
636

637
    #[test]
638
    fn activate_should_fail_if_at_the_active_plugins_limit_and_the_plugin_is_an_update_plugin() {
1✔
639
        let tmp_dir = tempdir().unwrap();
1✔
640
        let mut load_order = prepare(GameId::Starfield, tmp_dir.path());
1✔
641

1✔
642
        let plugins = prepare_bulk_full_plugins(&mut load_order);
1✔
643
        for plugin in &plugins[..254] {
254✔
644
            activate(&mut load_order, plugin).unwrap();
254✔
645
        }
254✔
646

647
        let plugin = "Blank - Override.esp";
1✔
648
        load_and_insert(&mut load_order, plugin);
1✔
649

1✔
650
        assert!(!load_order.is_active(plugin));
1✔
651

652
        assert!(activate(&mut load_order, plugin).is_err());
1✔
653
        assert!(!load_order.is_active(plugin));
1✔
654
    }
1✔
655

656
    #[test]
657
    fn activate_should_count_active_update_plugins_towards_limit() {
1✔
658
        let tmp_dir = tempdir().unwrap();
1✔
659
        let mut load_order = prepare(GameId::Starfield, tmp_dir.path());
1✔
660

1✔
661
        let plugins = prepare_bulk_full_plugins(&mut load_order);
1✔
662
        for plugin in &plugins[..254] {
254✔
663
            activate(&mut load_order, plugin).unwrap();
254✔
664
        }
254✔
665

666
        let plugin = "Blank - Override.esp";
1✔
667
        load_and_insert(&mut load_order, plugin);
1✔
668

1✔
669
        assert!(!load_order.is_active(plugin));
1✔
670

671
        assert!(activate(&mut load_order, plugin).is_err());
1✔
672
        assert!(!load_order.is_active(plugin));
1✔
673
    }
1✔
674

675
    #[test]
676
    fn activate_should_lower_the_full_plugin_limit_if_a_light_plugin_is_present() {
1✔
677
        let tmp_dir = tempdir().unwrap();
1✔
678
        let mut load_order = prepare(GameId::Starfield, tmp_dir.path());
1✔
679

1✔
680
        let plugins = prepare_bulk_full_plugins(&mut load_order);
1✔
681
        for plugin in &plugins[..252] {
252✔
682
            activate(&mut load_order, plugin).unwrap();
252✔
683
        }
252✔
684

685
        let plugin = "Blank.small.esm";
1✔
686
        load_and_insert(&mut load_order, plugin);
1✔
687
        activate(&mut load_order, plugin).unwrap();
1✔
688

1✔
689
        let plugin = &plugins[253];
1✔
690
        assert!(!load_order.is_active(plugin));
1✔
691

692
        assert!(activate(&mut load_order, plugin).is_ok());
1✔
693
        assert!(load_order.is_active(plugin));
1✔
694

695
        let plugin = &plugins[254];
1✔
696
        assert!(!load_order.is_active(plugin));
1✔
697

698
        assert!(activate(&mut load_order, plugin).is_err());
1✔
699
        assert!(!load_order.is_active(plugin));
1✔
700
    }
1✔
701

702
    #[test]
703
    fn activate_should_lower_the_full_plugin_limit_if_a_medium_plugin_is_present() {
1✔
704
        let tmp_dir = tempdir().unwrap();
1✔
705
        let mut load_order = prepare(GameId::Starfield, tmp_dir.path());
1✔
706

1✔
707
        let plugins = prepare_bulk_full_plugins(&mut load_order);
1✔
708
        for plugin in &plugins[..252] {
252✔
709
            activate(&mut load_order, plugin).unwrap();
252✔
710
        }
252✔
711

712
        let plugin = "Blank.medium.esm";
1✔
713
        load_and_insert(&mut load_order, plugin);
1✔
714
        activate(&mut load_order, plugin).unwrap();
1✔
715

1✔
716
        let plugin = &plugins[253];
1✔
717
        assert!(!load_order.is_active(plugin));
1✔
718

719
        assert!(activate(&mut load_order, plugin).is_ok());
1✔
720
        assert!(load_order.is_active(plugin));
1✔
721

722
        let plugin = &plugins[254];
1✔
723
        assert!(!load_order.is_active(plugin));
1✔
724

725
        assert!(activate(&mut load_order, plugin).is_err());
1✔
726
        assert!(!load_order.is_active(plugin));
1✔
727
    }
1✔
728

729
    #[test]
730
    fn activate_should_lower_the_full_plugin_limit_if_light_and_medium_plugins_are_present() {
1✔
731
        let tmp_dir = tempdir().unwrap();
1✔
732
        let mut load_order = prepare(GameId::Starfield, tmp_dir.path());
1✔
733

1✔
734
        let plugins = prepare_bulk_full_plugins(&mut load_order);
1✔
735
        for plugin in &plugins[..251] {
251✔
736
            activate(&mut load_order, plugin).unwrap();
251✔
737
        }
251✔
738

739
        for plugin in ["Blank.medium.esm", "Blank.small.esm"] {
2✔
740
            load_and_insert(&mut load_order, plugin);
2✔
741
            activate(&mut load_order, plugin).unwrap();
2✔
742
        }
2✔
743

744
        let plugin = &plugins[252];
1✔
745
        assert!(!load_order.is_active(plugin));
1✔
746

747
        assert!(activate(&mut load_order, plugin).is_ok());
1✔
748
        assert!(load_order.is_active(plugin));
1✔
749

750
        let plugin = &plugins[253];
1✔
751
        assert!(!load_order.is_active(plugin));
1✔
752

753
        assert!(activate(&mut load_order, plugin).is_err());
1✔
754
        assert!(!load_order.is_active(plugin));
1✔
755
    }
1✔
756

757
    #[test]
758
    fn activate_should_check_full_medium_and_small_plugins_active_limits_separately() {
1✔
759
        let tmp_dir = tempdir().unwrap();
1✔
760
        let mut load_order = prepare(GameId::Starfield, tmp_dir.path());
1✔
761

1✔
762
        let full = prepare_bulk_full_plugins(&mut load_order);
1✔
763
        let medium = prepare_bulk_medium_plugins(&mut load_order);
1✔
764
        let light = prepare_bulk_light_plugins(&mut load_order);
1✔
765

1✔
766
        let mut plugin_refs = Vec::with_capacity(4603);
1✔
767
        plugin_refs.extend(full[..252].iter().map(String::as_str));
1✔
768
        plugin_refs.extend(medium[..255].iter().map(String::as_str));
1✔
769
        plugin_refs.extend(light[..4095].iter().map(String::as_str));
1✔
770

1✔
771
        assert!(set_active_plugins(&mut load_order, &plugin_refs).is_ok());
1✔
772

773
        let plugin = &full[252];
1✔
774
        assert!(!load_order.is_active(plugin));
1✔
775
        assert!(activate(&mut load_order, plugin).is_ok());
1✔
776
        assert!(load_order.is_active(plugin));
1✔
777

778
        let plugin = &medium[255];
1✔
779
        assert!(!load_order.is_active(plugin));
1✔
780
        assert!(activate(&mut load_order, plugin).is_ok());
1✔
781
        assert!(load_order.is_active(plugin));
1✔
782

783
        let plugin = &light[4095];
1✔
784
        assert!(!load_order.is_active(plugin));
1✔
785
        assert!(activate(&mut load_order, plugin).is_ok());
1✔
786
        assert!(load_order.is_active(plugin));
1✔
787

788
        let plugin = &full[253];
1✔
789
        assert!(activate(&mut load_order, plugin).is_err());
1✔
790
        assert!(!load_order.is_active(plugin));
1✔
791

792
        let plugin = &medium[256];
1✔
793
        assert!(activate(&mut load_order, plugin).is_err());
1✔
794
        assert!(!load_order.is_active(plugin));
1✔
795

796
        let plugin = &light[4096];
1✔
797
        assert!(activate(&mut load_order, plugin).is_err());
1✔
798
        assert!(!load_order.is_active(plugin));
1✔
799
    }
1✔
800

801
    #[test]
802
    fn deactivate_should_deactivate_the_plugin_with_the_given_filename() {
1✔
803
        let tmp_dir = tempdir().unwrap();
1✔
804
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
805

1✔
806
        assert!(load_order.is_active("Blank.esp"));
1✔
807
        assert!(deactivate(&mut load_order, "Blank.esp").is_ok());
1✔
808
        assert!(!load_order.is_active("Blank.esp"));
1✔
809
    }
1✔
810

811
    #[test]
812
    fn deactivate_should_error_if_the_plugin_is_not_in_the_load_order() {
1✔
813
        let tmp_dir = tempdir().unwrap();
1✔
814
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
815

1✔
816
        assert!(deactivate(&mut load_order, "missing.esp").is_err());
1✔
817
        assert!(load_order.index_of("missing.esp").is_none());
1✔
818
    }
1✔
819

820
    #[test]
821
    fn deactivate_should_error_if_given_an_implicitly_active_plugin() {
1✔
822
        let tmp_dir = tempdir().unwrap();
1✔
823
        let mut load_order = prepare(GameId::SkyrimSE, tmp_dir.path());
1✔
824

1✔
825
        prepend_early_loader(&mut load_order);
1✔
826

1✔
827
        assert!(activate(&mut load_order, "Skyrim.esm").is_ok());
1✔
828
        assert!(deactivate(&mut load_order, "Skyrim.esm").is_err());
1✔
829
        assert!(load_order.is_active("Skyrim.esm"));
1✔
830
    }
1✔
831

832
    #[test]
833
    fn deactivate_should_error_if_given_a_missing_implicitly_active_plugin() {
1✔
834
        let tmp_dir = tempdir().unwrap();
1✔
835
        let mut load_order = prepare(GameId::Skyrim, tmp_dir.path());
1✔
836

1✔
837
        assert!(deactivate(&mut load_order, "Update.esm").is_err());
1✔
838
        assert!(load_order.index_of("Update.esm").is_none());
1✔
839
    }
1✔
840

841
    #[test]
842
    fn deactivate_should_do_nothing_if_the_plugin_is_inactive() {
1✔
843
        let tmp_dir = tempdir().unwrap();
1✔
844
        let mut load_order = prepare(GameId::Skyrim, tmp_dir.path());
1✔
845

1✔
846
        assert!(!load_order.is_active("Blank - Different.esp"));
1✔
847
        assert!(deactivate(&mut load_order, "Blank - Different.esp").is_ok());
1✔
848
        assert!(!load_order.is_active("Blank - Different.esp"));
1✔
849
    }
1✔
850

851
    #[test]
852
    fn set_active_plugins_should_error_if_passed_an_invalid_plugin_name() {
1✔
853
        let tmp_dir = tempdir().unwrap();
1✔
854
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
855

1✔
856
        let active_plugins = ["missing.esp"];
1✔
857
        assert!(set_active_plugins(&mut load_order, &active_plugins).is_err());
1✔
858
        assert_eq!(1, load_order.active_plugin_names().len());
1✔
859
    }
1✔
860

861
    #[test]
862
    fn set_active_plugins_should_error_if_the_given_plugins_are_missing_implicitly_active_plugins()
1✔
863
    {
1✔
864
        let tmp_dir = tempdir().unwrap();
1✔
865
        let mut load_order = prepare(GameId::SkyrimSE, tmp_dir.path());
1✔
866

1✔
867
        prepend_early_loader(&mut load_order);
1✔
868

1✔
869
        let active_plugins = ["Blank.esp"];
1✔
870
        assert!(set_active_plugins(&mut load_order, &active_plugins).is_err());
1✔
871
        assert_eq!(1, load_order.active_plugin_names().len());
1✔
872
    }
1✔
873

874
    #[test]
875
    fn set_active_plugins_should_error_if_a_missing_implicitly_active_plugin_is_given() {
1✔
876
        let tmp_dir = tempdir().unwrap();
1✔
877
        let mut load_order = prepare(GameId::Skyrim, tmp_dir.path());
1✔
878

1✔
879
        let active_plugins = ["Update.esm", "Blank.esp"];
1✔
880
        assert!(set_active_plugins(&mut load_order, &active_plugins).is_err());
1✔
881
        assert_eq!(1, load_order.active_plugin_names().len());
1✔
882
    }
1✔
883

884
    #[test]
885
    fn set_active_plugins_should_error_if_given_plugins_not_in_the_load_order() {
1✔
886
        let tmp_dir = tempdir().unwrap();
1✔
887
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
888

1✔
889
        let active_plugins = ["Blank - Master Dependent.esp", "Blàñk.esp"];
1✔
890
        assert!(set_active_plugins(&mut load_order, &active_plugins).is_err());
1✔
891
        assert!(!load_order.is_active("Blank - Master Dependent.esp"));
1✔
892
        assert!(load_order
1✔
893
            .index_of("Blank - Master Dependent.esp")
1✔
894
            .is_none());
1✔
895
        assert!(!load_order.is_active("Blàñk.esp"));
1✔
896
        assert!(load_order.index_of("Blàñk.esp").is_none());
1✔
897
    }
1✔
898

899
    #[test]
900
    fn set_active_plugins_should_deactivate_all_plugins_not_given() {
1✔
901
        let tmp_dir = tempdir().unwrap();
1✔
902
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
903

1✔
904
        let active_plugins = ["Blank - Different.esp"];
1✔
905
        assert!(load_order.is_active("Blank.esp"));
1✔
906
        assert!(set_active_plugins(&mut load_order, &active_plugins).is_ok());
1✔
907
        assert!(!load_order.is_active("Blank.esp"));
1✔
908
    }
1✔
909

910
    #[test]
911
    fn set_active_plugins_should_activate_all_given_plugins() {
1✔
912
        let tmp_dir = tempdir().unwrap();
1✔
913
        let mut load_order = prepare(GameId::Oblivion, tmp_dir.path());
1✔
914

1✔
915
        let active_plugins = ["Blank - Different.esp"];
1✔
916
        assert!(!load_order.is_active("Blank - Different.esp"));
1✔
917
        assert!(set_active_plugins(&mut load_order, &active_plugins).is_ok());
1✔
918
        assert!(load_order.is_active("Blank - Different.esp"));
1✔
919
    }
1✔
920

921
    #[test]
922
    fn set_active_plugins_should_count_update_plugins_towards_limit() {
1✔
923
        let tmp_dir = tempdir().unwrap();
1✔
924
        let mut load_order = prepare(GameId::Starfield, tmp_dir.path());
1✔
925

1✔
926
        let blank_override = "Blank - Override.esp";
1✔
927
        load_and_insert(&mut load_order, blank_override);
1✔
928

1✔
929
        let mut active_plugins = vec![blank_override.to_string()];
1✔
930

1✔
931
        let plugins = prepare_bulk_full_plugins(&mut load_order);
1✔
932
        for plugin in plugins.into_iter().take(255) {
255✔
933
            active_plugins.push(plugin);
255✔
934
        }
255✔
935

936
        let active_plugins: Vec<&str> = active_plugins.iter().map(|s| s.as_str()).collect();
256✔
937

1✔
938
        assert!(set_active_plugins(&mut load_order, &active_plugins).is_err());
1✔
939
        assert_eq!(1, load_order.active_plugin_names().len());
1✔
940
    }
1✔
941

942
    #[test]
943
    fn set_active_plugins_should_lower_the_full_plugin_limit_if_a_light_plugin_is_present() {
1✔
944
        let tmp_dir = tempdir().unwrap();
1✔
945
        let mut load_order = prepare(GameId::Starfield, tmp_dir.path());
1✔
946

1✔
947
        let full = prepare_bulk_full_plugins(&mut load_order);
1✔
948

1✔
949
        let plugin = "Blank.small.esm";
1✔
950
        load_and_insert(&mut load_order, plugin);
1✔
951

1✔
952
        let mut plugin_refs = vec![plugin];
1✔
953
        plugin_refs.extend(full[..254].iter().map(String::as_str));
1✔
954

1✔
955
        assert!(set_active_plugins(&mut load_order, &plugin_refs).is_ok());
1✔
956
        assert_eq!(255, load_order.active_plugin_names().len());
1✔
957

958
        plugin_refs.push(full[254].as_str());
1✔
959

1✔
960
        assert!(set_active_plugins(&mut load_order, &plugin_refs).is_err());
1✔
961
        assert_eq!(255, load_order.active_plugin_names().len());
1✔
962
    }
1✔
963

964
    #[test]
965
    fn set_active_plugins_should_lower_the_full_plugin_limit_if_a_medium_plugin_is_present() {
1✔
966
        let tmp_dir = tempdir().unwrap();
1✔
967
        let mut load_order = prepare(GameId::Starfield, tmp_dir.path());
1✔
968

1✔
969
        let full = prepare_bulk_full_plugins(&mut load_order);
1✔
970

1✔
971
        let plugin = "Blank.medium.esm";
1✔
972
        load_and_insert(&mut load_order, plugin);
1✔
973

1✔
974
        let mut plugin_refs = vec![plugin];
1✔
975
        plugin_refs.extend(full[..254].iter().map(String::as_str));
1✔
976

1✔
977
        assert!(set_active_plugins(&mut load_order, &plugin_refs).is_ok());
1✔
978
        assert_eq!(255, load_order.active_plugin_names().len());
1✔
979

980
        plugin_refs.push(full[254].as_str());
1✔
981

1✔
982
        assert!(set_active_plugins(&mut load_order, &plugin_refs).is_err());
1✔
983
        assert_eq!(255, load_order.active_plugin_names().len());
1✔
984
    }
1✔
985

986
    #[test]
987
    fn set_active_plugins_should_lower_the_full_plugin_limit_if_light_and_plugins_are_present() {
1✔
988
        let tmp_dir = tempdir().unwrap();
1✔
989
        let mut load_order = prepare(GameId::Starfield, tmp_dir.path());
1✔
990

1✔
991
        let full = prepare_bulk_full_plugins(&mut load_order);
1✔
992

1✔
993
        let medium_plugin = "Blank.medium.esm";
1✔
994
        let light_plugin = "Blank.small.esm";
1✔
995
        load_and_insert(&mut load_order, medium_plugin);
1✔
996
        load_and_insert(&mut load_order, light_plugin);
1✔
997

1✔
998
        let mut plugin_refs = vec![medium_plugin, light_plugin];
1✔
999
        plugin_refs.extend(full[..253].iter().map(String::as_str));
1✔
1000

1✔
1001
        assert!(set_active_plugins(&mut load_order, &plugin_refs).is_ok());
1✔
1002
        assert_eq!(255, load_order.active_plugin_names().len());
1✔
1003

1004
        plugin_refs.push(full[253].as_str());
1✔
1005

1✔
1006
        assert!(set_active_plugins(&mut load_order, &plugin_refs).is_err());
1✔
1007
        assert_eq!(255, load_order.active_plugin_names().len());
1✔
1008
    }
1✔
1009

1010
    #[test]
1011
    fn set_active_plugins_should_count_full_medium_and_small_plugins_separately() {
1✔
1012
        let tmp_dir = tempdir().unwrap();
1✔
1013
        let mut load_order = prepare(GameId::Starfield, tmp_dir.path());
1✔
1014

1✔
1015
        let full = prepare_bulk_full_plugins(&mut load_order);
1✔
1016
        let medium = prepare_bulk_medium_plugins(&mut load_order);
1✔
1017
        let light = prepare_bulk_light_plugins(&mut load_order);
1✔
1018

1✔
1019
        let mut plugin_refs = Vec::with_capacity(4064);
1✔
1020
        plugin_refs.extend(full[..252].iter().map(String::as_str));
1✔
1021
        plugin_refs.extend(medium[..256].iter().map(String::as_str));
1✔
1022
        plugin_refs.extend(light[..4096].iter().map(String::as_str));
1✔
1023

1✔
1024
        assert!(set_active_plugins(&mut load_order, &plugin_refs).is_ok());
1✔
1025
        assert_eq!(4604, load_order.active_plugin_names().len());
1✔
1026
    }
1✔
1027

1028
    #[test]
1029
    fn set_active_plugins_should_error_if_given_more_than_254_full_plugins() {
1✔
1030
        let tmp_dir = tempdir().unwrap();
1✔
1031
        let mut load_order = prepare(GameId::Starfield, tmp_dir.path());
1✔
1032

1✔
1033
        let full = prepare_bulk_full_plugins(&mut load_order);
1✔
1034

1✔
1035
        let plugin_refs: Vec<_> = full[..256].iter().map(String::as_str).collect();
1✔
1036

1✔
1037
        assert!(set_active_plugins(&mut load_order, &plugin_refs).is_err());
1✔
1038
        assert_eq!(1, load_order.active_plugin_names().len());
1✔
1039
    }
1✔
1040

1041
    #[test]
1042
    fn set_active_plugins_should_error_if_given_more_than_256_medium_plugins() {
1✔
1043
        let tmp_dir = tempdir().unwrap();
1✔
1044
        let mut load_order = prepare(GameId::Starfield, tmp_dir.path());
1✔
1045

1✔
1046
        let medium = prepare_bulk_medium_plugins(&mut load_order);
1✔
1047

1✔
1048
        let plugin_refs: Vec<_> = medium[..257].iter().map(String::as_str).collect();
1✔
1049

1✔
1050
        assert!(set_active_plugins(&mut load_order, &plugin_refs).is_err());
1✔
1051
        assert_eq!(1, load_order.active_plugin_names().len());
1✔
1052
    }
1✔
1053

1054
    #[test]
1055
    fn set_active_plugins_should_error_if_given_more_than_4096_light_plugins() {
1✔
1056
        let tmp_dir = tempdir().unwrap();
1✔
1057
        let mut load_order = prepare(GameId::Starfield, tmp_dir.path());
1✔
1058

1✔
1059
        let light = prepare_bulk_light_plugins(&mut load_order);
1✔
1060

1✔
1061
        let plugin_refs: Vec<_> = light[..4097].iter().map(String::as_str).collect();
1✔
1062

1✔
1063
        assert!(set_active_plugins(&mut load_order, &plugin_refs).is_err());
1✔
1064
        assert_eq!(1, load_order.active_plugin_names().len());
1✔
1065
    }
1✔
1066
}
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

© 2026 Coveralls, Inc