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

loot / loot-condition-interpreter / 5896638595

17 Aug 2023 10:39PM UTC coverage: 89.816% (-0.04%) from 89.858%
5896638595

push

github

Ortham
Remove support for the "LOOT" alias

24 of 24 new or added lines in 4 files covered. (100.0%)

3995 of 4448 relevant lines covered (89.82%)

14.9 hits per line

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

99.27
/src/function/path.rs
1
use std::{
2
    ffi::OsStr,
3
    path::{Path, PathBuf},
4
};
5

6
use crate::{GameType, State};
7

8
const GHOST_EXTENSION: &str = "ghost";
9
const GHOST_EXTENSION_WITH_PERIOD: &str = ".ghost";
10

11
fn is_unghosted_plugin_file_extension(game_type: GameType, extension: &str) -> bool {
12
    match extension {
9✔
13
        "esp" | "esm" => true,
71✔
14
        "esl" if game_type.supports_light_plugins() => true,
37✔
15
        _ => false,
33✔
16
    }
17
}
71✔
18

19
fn has_unghosted_plugin_file_extension(game_type: GameType, path: &Path) -> bool {
32✔
20
    match path.extension().and_then(OsStr::to_str) {
32✔
21
        Some(ext) => is_unghosted_plugin_file_extension(game_type, ext),
17✔
22
        _ => false,
15✔
23
    }
24
}
32✔
25

26
pub fn has_plugin_file_extension(game_type: GameType, path: &Path) -> bool {
13✔
27
    match path.extension().and_then(OsStr::to_str) {
13✔
28
        Some(GHOST_EXTENSION) => path
12✔
29
            .file_stem()
3✔
30
            .map(|s| has_unghosted_plugin_file_extension(game_type, Path::new(s)))
3✔
31
            .unwrap_or(false),
3✔
32
        Some(ext) => is_unghosted_plugin_file_extension(game_type, ext),
9✔
33
        _ => false,
1✔
34
    }
35
}
13✔
36

37
fn add_ghost_extension(path: PathBuf) -> PathBuf {
6✔
38
    match path.extension() {
6✔
39
        Some(e) => {
5✔
40
            let mut new_extension = e.to_os_string();
5✔
41
            new_extension.push(GHOST_EXTENSION_WITH_PERIOD);
5✔
42
            path.with_extension(&new_extension)
5✔
43
        }
44
        None => path.with_extension(GHOST_EXTENSION),
1✔
45
    }
46
}
6✔
47

48
pub fn normalise_file_name(game_type: GameType, name: &str) -> &str {
49
    if let Some(stem) = name.strip_suffix(GHOST_EXTENSION_WITH_PERIOD) {
59✔
50
        if has_unghosted_plugin_file_extension(game_type, Path::new(stem)) {
3✔
51
            return stem;
3✔
52
        }
×
53
    }
56✔
54

55
    name
56✔
56
}
59✔
57

58
pub fn resolve_path(state: &State, path: &Path) -> PathBuf {
74✔
59
    // First check external data paths, as files there may override files in the main data path.
60
    for data_path in &state.additional_data_paths {
75✔
61
        let mut path = data_path.join(path);
2✔
62

2✔
63
        if path.exists() {
2✔
64
            return path;
1✔
65
        }
1✔
66

1✔
67
        if has_unghosted_plugin_file_extension(state.game_type, &path) {
1✔
68
            path = add_ghost_extension(path);
×
69
        }
1✔
70

71
        if path.exists() {
1✔
72
            return path;
×
73
        }
1✔
74
    }
75

76
    // Now check the main data path.
77
    let path = state.data_path.join(path);
73✔
78

73✔
79
    if !path.exists() && has_unghosted_plugin_file_extension(state.game_type, &path) {
73✔
80
        add_ghost_extension(path)
4✔
81
    } else {
82
        path
69✔
83
    }
84
}
74✔
85

86
#[cfg(test)]
87
mod tests {
88
    use super::*;
89

90
    #[test]
1✔
91
    fn is_unghosted_plugin_file_extension_should_be_true_for_esp_for_all_game_types() {
1✔
92
        let extension = "esp";
1✔
93

1✔
94
        assert!(is_unghosted_plugin_file_extension(
1✔
95
            GameType::Morrowind,
1✔
96
            extension
1✔
97
        ));
1✔
98
        assert!(is_unghosted_plugin_file_extension(
1✔
99
            GameType::Oblivion,
1✔
100
            extension
1✔
101
        ));
1✔
102
        assert!(is_unghosted_plugin_file_extension(
1✔
103
            GameType::Skyrim,
1✔
104
            extension
1✔
105
        ));
1✔
106
        assert!(is_unghosted_plugin_file_extension(
1✔
107
            GameType::SkyrimSE,
1✔
108
            extension
1✔
109
        ));
1✔
110
        assert!(is_unghosted_plugin_file_extension(
1✔
111
            GameType::SkyrimVR,
1✔
112
            extension
1✔
113
        ));
1✔
114
        assert!(is_unghosted_plugin_file_extension(
1✔
115
            GameType::Fallout3,
1✔
116
            extension
1✔
117
        ));
1✔
118
        assert!(is_unghosted_plugin_file_extension(
1✔
119
            GameType::FalloutNV,
1✔
120
            extension
1✔
121
        ));
1✔
122
        assert!(is_unghosted_plugin_file_extension(
1✔
123
            GameType::Fallout4,
1✔
124
            extension
1✔
125
        ));
1✔
126
        assert!(is_unghosted_plugin_file_extension(
1✔
127
            GameType::Fallout4VR,
1✔
128
            extension
1✔
129
        ));
1✔
130
    }
1✔
131

132
    #[test]
1✔
133
    fn is_unghosted_plugin_file_extension_should_be_true_for_esm_for_all_game_types() {
1✔
134
        let extension = "esm";
1✔
135

1✔
136
        assert!(is_unghosted_plugin_file_extension(
1✔
137
            GameType::Morrowind,
1✔
138
            extension
1✔
139
        ));
1✔
140
        assert!(is_unghosted_plugin_file_extension(
1✔
141
            GameType::Oblivion,
1✔
142
            extension
1✔
143
        ));
1✔
144
        assert!(is_unghosted_plugin_file_extension(
1✔
145
            GameType::Skyrim,
1✔
146
            extension
1✔
147
        ));
1✔
148
        assert!(is_unghosted_plugin_file_extension(
1✔
149
            GameType::SkyrimSE,
1✔
150
            extension
1✔
151
        ));
1✔
152
        assert!(is_unghosted_plugin_file_extension(
1✔
153
            GameType::SkyrimVR,
1✔
154
            extension
1✔
155
        ));
1✔
156
        assert!(is_unghosted_plugin_file_extension(
1✔
157
            GameType::Fallout3,
1✔
158
            extension
1✔
159
        ));
1✔
160
        assert!(is_unghosted_plugin_file_extension(
1✔
161
            GameType::FalloutNV,
1✔
162
            extension
1✔
163
        ));
1✔
164
        assert!(is_unghosted_plugin_file_extension(
1✔
165
            GameType::Fallout4,
1✔
166
            extension
1✔
167
        ));
1✔
168
        assert!(is_unghosted_plugin_file_extension(
1✔
169
            GameType::Fallout4VR,
1✔
170
            extension
1✔
171
        ));
1✔
172
    }
1✔
173

174
    #[test]
1✔
175
    fn is_unghosted_plugin_file_extension_should_be_true_for_esl_for_tes5se_tes5vr_fo4_and_fo4vr() {
1✔
176
        let extension = "esl";
1✔
177

1✔
178
        assert!(is_unghosted_plugin_file_extension(
1✔
179
            GameType::SkyrimSE,
1✔
180
            extension
1✔
181
        ));
1✔
182
        assert!(is_unghosted_plugin_file_extension(
1✔
183
            GameType::SkyrimVR,
1✔
184
            extension
1✔
185
        ));
1✔
186
        assert!(is_unghosted_plugin_file_extension(
1✔
187
            GameType::Fallout4,
1✔
188
            extension
1✔
189
        ));
1✔
190
        assert!(is_unghosted_plugin_file_extension(
1✔
191
            GameType::Fallout4VR,
1✔
192
            extension
1✔
193
        ));
1✔
194
    }
1✔
195

196
    #[test]
1✔
197
    fn is_unghosted_plugin_file_extension_should_be_false_for_esl_for_tes3_to_5_fo3_and_fonv() {
1✔
198
        let extension = "esl";
1✔
199

1✔
200
        assert!(!is_unghosted_plugin_file_extension(
1✔
201
            GameType::Morrowind,
1✔
202
            extension
1✔
203
        ));
1✔
204
        assert!(!is_unghosted_plugin_file_extension(
1✔
205
            GameType::Oblivion,
1✔
206
            extension
1✔
207
        ));
1✔
208
        assert!(!is_unghosted_plugin_file_extension(
1✔
209
            GameType::Skyrim,
1✔
210
            extension
1✔
211
        ));
1✔
212
        assert!(!is_unghosted_plugin_file_extension(
1✔
213
            GameType::Fallout3,
1✔
214
            extension
1✔
215
        ));
1✔
216
        assert!(!is_unghosted_plugin_file_extension(
1✔
217
            GameType::FalloutNV,
1✔
218
            extension
1✔
219
        ));
1✔
220
    }
1✔
221

222
    #[test]
1✔
223
    fn is_unghosted_plugin_file_extension_should_be_false_for_ghost_for_all_game_types() {
1✔
224
        let extension = "ghost";
1✔
225

1✔
226
        assert!(!is_unghosted_plugin_file_extension(
1✔
227
            GameType::Morrowind,
1✔
228
            extension
1✔
229
        ));
1✔
230
        assert!(!is_unghosted_plugin_file_extension(
1✔
231
            GameType::Oblivion,
1✔
232
            extension
1✔
233
        ));
1✔
234
        assert!(!is_unghosted_plugin_file_extension(
1✔
235
            GameType::Skyrim,
1✔
236
            extension
1✔
237
        ));
1✔
238
        assert!(!is_unghosted_plugin_file_extension(
1✔
239
            GameType::SkyrimSE,
1✔
240
            extension
1✔
241
        ));
1✔
242
        assert!(!is_unghosted_plugin_file_extension(
1✔
243
            GameType::SkyrimVR,
1✔
244
            extension
1✔
245
        ));
1✔
246
        assert!(!is_unghosted_plugin_file_extension(
1✔
247
            GameType::Fallout3,
1✔
248
            extension
1✔
249
        ));
1✔
250
        assert!(!is_unghosted_plugin_file_extension(
1✔
251
            GameType::FalloutNV,
1✔
252
            extension
1✔
253
        ));
1✔
254
        assert!(!is_unghosted_plugin_file_extension(
1✔
255
            GameType::Fallout4,
1✔
256
            extension
1✔
257
        ));
1✔
258
        assert!(!is_unghosted_plugin_file_extension(
1✔
259
            GameType::Fallout4VR,
1✔
260
            extension
1✔
261
        ));
1✔
262
    }
1✔
263

264
    #[test]
1✔
265
    fn is_unghosted_plugin_file_extension_should_be_false_for_non_esp_esm_esl_for_all_game_types() {
1✔
266
        let extension = "txt";
1✔
267

1✔
268
        assert!(!is_unghosted_plugin_file_extension(
1✔
269
            GameType::Morrowind,
1✔
270
            extension
1✔
271
        ));
1✔
272
        assert!(!is_unghosted_plugin_file_extension(
1✔
273
            GameType::Oblivion,
1✔
274
            extension
1✔
275
        ));
1✔
276
        assert!(!is_unghosted_plugin_file_extension(
1✔
277
            GameType::Skyrim,
1✔
278
            extension
1✔
279
        ));
1✔
280
        assert!(!is_unghosted_plugin_file_extension(
1✔
281
            GameType::SkyrimSE,
1✔
282
            extension
1✔
283
        ));
1✔
284
        assert!(!is_unghosted_plugin_file_extension(
1✔
285
            GameType::SkyrimVR,
1✔
286
            extension
1✔
287
        ));
1✔
288
        assert!(!is_unghosted_plugin_file_extension(
1✔
289
            GameType::Fallout3,
1✔
290
            extension
1✔
291
        ));
1✔
292
        assert!(!is_unghosted_plugin_file_extension(
1✔
293
            GameType::FalloutNV,
1✔
294
            extension
1✔
295
        ));
1✔
296
        assert!(!is_unghosted_plugin_file_extension(
1✔
297
            GameType::Fallout4,
1✔
298
            extension
1✔
299
        ));
1✔
300
        assert!(!is_unghosted_plugin_file_extension(
1✔
301
            GameType::Fallout4VR,
1✔
302
            extension
1✔
303
        ));
1✔
304
    }
1✔
305

306
    #[test]
1✔
307
    fn has_unghosted_plugin_file_extension_should_return_false_if_the_path_has_no_extension() {
1✔
308
        assert!(!has_unghosted_plugin_file_extension(
1✔
309
            GameType::Skyrim,
1✔
310
            Path::new("file")
1✔
311
        ));
1✔
312
    }
1✔
313

314
    #[test]
1✔
315
    fn has_unghosted_plugin_file_extension_should_return_false_if_the_path_has_a_non_plugin_extension(
1✔
316
    ) {
1✔
317
        assert!(!has_unghosted_plugin_file_extension(
1✔
318
            GameType::Skyrim,
1✔
319
            Path::new("plugin.bsa")
1✔
320
        ));
1✔
321
    }
1✔
322

323
    #[test]
1✔
324
    fn has_unghosted_plugin_file_extension_should_return_false_if_the_path_has_a_ghosted_plugin_extension(
1✔
325
    ) {
1✔
326
        assert!(!has_unghosted_plugin_file_extension(
1✔
327
            GameType::Skyrim,
1✔
328
            Path::new("plugin.esp.ghost")
1✔
329
        ));
1✔
330
    }
1✔
331

332
    #[test]
1✔
333
    fn has_unghosted_plugin_file_extension_should_return_true_if_the_path_has_an_unghosted_plugin_extension(
1✔
334
    ) {
1✔
335
        assert!(has_unghosted_plugin_file_extension(
1✔
336
            GameType::Skyrim,
1✔
337
            Path::new("plugin.esp")
1✔
338
        ));
1✔
339
    }
1✔
340

341
    #[test]
1✔
342
    fn has_plugin_file_extension_should_return_true_if_the_path_has_an_unghosted_plugin_extension()
1✔
343
    {
1✔
344
        assert!(has_plugin_file_extension(
1✔
345
            GameType::Skyrim,
1✔
346
            Path::new("plugin.esp")
1✔
347
        ));
1✔
348
    }
1✔
349

350
    #[test]
1✔
351
    fn has_plugin_file_extension_should_return_true_if_the_path_has_a_ghosted_plugin_extension() {
1✔
352
        assert!(has_plugin_file_extension(
1✔
353
            GameType::Skyrim,
1✔
354
            Path::new("plugin.esp.ghost")
1✔
355
        ));
1✔
356
    }
1✔
357

358
    #[test]
1✔
359
    fn has_plugin_file_extension_should_return_false_if_the_path_has_a_non_plugin_extension() {
1✔
360
        assert!(!has_plugin_file_extension(
1✔
361
            GameType::Skyrim,
1✔
362
            Path::new("plugin.bsa")
1✔
363
        ));
1✔
364
    }
1✔
365

366
    #[test]
1✔
367
    fn has_plugin_file_extension_should_return_false_if_the_path_has_a_ghosted_non_plugin_extension(
1✔
368
    ) {
1✔
369
        assert!(!has_plugin_file_extension(
1✔
370
            GameType::Skyrim,
1✔
371
            Path::new("plugin.bsa.ghost")
1✔
372
        ));
1✔
373
    }
1✔
374

375
    #[test]
1✔
376
    fn has_plugin_file_extension_should_return_false_if_the_path_has_only_ghost_extension() {
1✔
377
        assert!(!has_plugin_file_extension(
1✔
378
            GameType::Skyrim,
1✔
379
            Path::new("plugin.ghost")
1✔
380
        ));
1✔
381
    }
1✔
382

383
    #[test]
1✔
384
    fn has_plugin_file_extension_should_return_false_if_the_path_has_no_extension() {
1✔
385
        assert!(!has_plugin_file_extension(
1✔
386
            GameType::Skyrim,
1✔
387
            Path::new("plugin")
1✔
388
        ));
1✔
389
    }
1✔
390

391
    #[test]
1✔
392
    fn add_ghost_extension_should_add_dot_ghost_to_an_existing_extension() {
1✔
393
        let path = add_ghost_extension("plugin.esp".into());
1✔
394
        assert_eq!(PathBuf::from("plugin.esp.ghost"), path);
1✔
395
    }
1✔
396

397
    #[test]
1✔
398
    fn add_ghost_extension_should_add_dot_ghost_to_an_a_path_with_no_extension() {
1✔
399
        let path = add_ghost_extension("plugin".into());
1✔
400
        assert_eq!(PathBuf::from("plugin.ghost"), path);
1✔
401
    }
1✔
402

403
    #[test]
1✔
404
    fn resolve_path_should_return_the_data_path_prefixed_path_if_it_exists() {
1✔
405
        let data_path = PathBuf::from(".");
1✔
406
        let state = State::new(GameType::Skyrim, data_path.clone());
1✔
407
        let input_path = Path::new("README.md");
1✔
408
        let resolved_path = resolve_path(&state, input_path);
1✔
409

1✔
410
        assert_eq!(data_path.join(input_path), resolved_path);
1✔
411
    }
1✔
412

413
    #[test]
1✔
414
    fn resolve_path_should_return_the_data_path_prefixed_path_if_it_does_not_exist_and_is_not_an_unghosted_plugin_filename(
1✔
415
    ) {
1✔
416
        let data_path = PathBuf::from(".");
1✔
417
        let state = State::new(GameType::Skyrim, data_path.clone());
1✔
418
        let input_path = Path::new("plugin.esp.ghost");
1✔
419
        let resolved_path = resolve_path(&state, input_path);
1✔
420

1✔
421
        assert_eq!(data_path.join(input_path), resolved_path);
1✔
422

423
        let input_path = Path::new("file.txt");
1✔
424
        let resolved_path = resolve_path(&state, input_path);
1✔
425

1✔
426
        assert_eq!(data_path.join(input_path), resolved_path);
1✔
427
    }
1✔
428

429
    #[test]
1✔
430
    fn resolve_path_should_return_the_given_data_relative_path_plus_a_ghost_extension_if_the_plugin_path_does_not_exist(
1✔
431
    ) {
1✔
432
        let data_path = PathBuf::from(".");
1✔
433
        let state = State::new(GameType::Skyrim, data_path.clone());
1✔
434
        let input_path = Path::new("plugin.esp");
1✔
435
        let resolved_path = resolve_path(&state, input_path);
1✔
436

1✔
437
        assert_eq!(
1✔
438
            data_path.join(input_path.with_extension("esp.ghost")),
1✔
439
            resolved_path
1✔
440
        );
1✔
441
    }
1✔
442

443
    #[test]
1✔
444
    fn resolve_path_should_check_external_data_paths_in_order_before_data_path() {
1✔
445
        use std::fs::copy;
1✔
446
        use std::fs::create_dir;
1✔
447

1✔
448
        let tmp_dir = tempfile::tempdir().unwrap();
1✔
449
        let external_data_path_1 = tmp_dir.path().join("Data1");
1✔
450
        let external_data_path_2 = tmp_dir.path().join("Data2");
1✔
451
        let data_path = tmp_dir.path().join("Data3");
1✔
452

1✔
453
        create_dir(&external_data_path_1).unwrap();
1✔
454
        create_dir(&external_data_path_2).unwrap();
1✔
455
        create_dir(&data_path).unwrap();
1✔
456
        copy(
1✔
457
            Path::new("Cargo.toml"),
1✔
458
            external_data_path_2.join("Cargo.toml"),
1✔
459
        )
1✔
460
        .unwrap();
1✔
461
        copy(Path::new("Cargo.toml"), data_path.join("Cargo.toml")).unwrap();
1✔
462

1✔
463
        let mut state = State::new(GameType::Skyrim, data_path);
1✔
464
        state.set_additional_data_paths(vec![external_data_path_1, external_data_path_2.clone()]);
1✔
465

1✔
466
        let input_path = Path::new("Cargo.toml");
1✔
467
        let resolved_path = resolve_path(&state, input_path);
1✔
468

1✔
469
        assert_eq!(external_data_path_2.join(input_path), resolved_path);
1✔
470
    }
1✔
471
}
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