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

Ortham / libloadorder / 9669712859

25 Jun 2024 09:15PM UTC coverage: 91.599% (+4.7%) from 86.942%
9669712859

push

github

Ortham
Use Starfield plugins in Starfield tests

65 of 65 new or added lines in 5 files covered. (100.0%)

163 existing lines in 11 files now uncovered.

7218 of 7880 relevant lines covered (91.6%)

66616.03 hits per line

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

66.2
/src/enums.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

20
use std::convert::From;
21
use std::error;
22
use std::ffi::OsString;
23
use std::fmt;
24
use std::io;
25
use std::path::PathBuf;
26
use std::string::FromUtf8Error;
27
use std::time;
28

29
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
30
pub enum LoadOrderMethod {
31
    Timestamp,
32
    Textfile,
33
    Asterisk,
34
}
35

36
#[allow(clippy::upper_case_acronyms)]
37
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
38
pub enum GameId {
39
    Morrowind = 1,
40
    Oblivion,
41
    Skyrim,
42
    Fallout3,
43
    FalloutNV,
44
    Fallout4,
45
    SkyrimSE,
46
    Fallout4VR,
47
    SkyrimVR,
48
    Starfield,
49
}
50

51
impl GameId {
52
    pub fn to_esplugin_id(self) -> esplugin::GameId {
12,896✔
53
        match self {
12,896✔
54
            GameId::Morrowind => esplugin::GameId::Morrowind,
92✔
55
            GameId::Oblivion => esplugin::GameId::Oblivion,
844✔
56
            GameId::Skyrim => esplugin::GameId::Skyrim,
270✔
57
            GameId::SkyrimSE => esplugin::GameId::SkyrimSE,
10,850✔
58
            GameId::SkyrimVR => esplugin::GameId::SkyrimSE,
4✔
59
            GameId::Fallout3 => esplugin::GameId::Fallout3,
1✔
60
            GameId::FalloutNV => esplugin::GameId::FalloutNV,
1✔
61
            GameId::Fallout4 => esplugin::GameId::Fallout4,
42✔
62
            GameId::Fallout4VR => esplugin::GameId::Fallout4,
9✔
63
            GameId::Starfield => esplugin::GameId::Starfield,
783✔
64
        }
65
    }
12,896✔
66

67
    pub fn supports_light_plugins(self) -> bool {
23,888✔
68
        use self::GameId::*;
69
        matches!(
1,423✔
70
            self,
23,888✔
71
            Fallout4 | Fallout4VR | SkyrimSE | SkyrimVR | Starfield
72
        )
73
    }
23,888✔
74
}
75

76
#[derive(Debug)]
77
pub enum Error {
78
    InvalidPath(PathBuf),
79
    IoError(PathBuf, io::Error),
80
    NoFilename(PathBuf),
81
    SystemTimeError(time::SystemTimeError),
82
    NotUtf8(Vec<u8>),
83
    DecodeError(Vec<u8>),
84
    EncodeError(String),
85
    PluginParsingError(PathBuf, Box<dyn error::Error + Send>),
86
    PluginNotFound(String),
87
    TooManyActivePlugins {
88
        light_count: usize,
89
        normal_count: usize,
90
    },
91
    DuplicatePlugin(String),
92
    NonMasterBeforeMaster {
93
        master: String,
94
        non_master: String,
95
    },
96
    GameMasterMustLoadFirst(String),
97
    InvalidEarlyLoadingPluginPosition {
98
        name: String,
99
        pos: usize,
100
        expected_pos: usize,
101
    },
102
    ImplicitlyActivePlugin(String),
103
    NoLocalAppData,
104
    NoDocumentsPath,
105
    UnrepresentedHoist {
106
        plugin: String,
107
        master: String,
108
    },
109
    InstalledPlugin(String),
110
    IniParsingError {
111
        path: PathBuf,
112
        line: usize,
113
        column: usize,
114
        message: String,
115
    },
116
    VdfParsingError(PathBuf, String),
117
    SystemError(i32, OsString),
118
}
119

120
impl From<time::SystemTimeError> for Error {
UNCOV
121
    fn from(error: time::SystemTimeError) -> Self {
×
UNCOV
122
        Error::SystemTimeError(error)
×
UNCOV
123
    }
×
124
}
125

126
impl From<FromUtf8Error> for Error {
UNCOV
127
    fn from(error: FromUtf8Error) -> Self {
×
UNCOV
128
        Error::NotUtf8(error.into_bytes())
×
UNCOV
129
    }
×
130
}
131

132
#[cfg(windows)]
133
impl From<windows::core::Error> for Error {
134
    fn from(error: windows::core::Error) -> Self {
135
        Error::SystemError(error.code().0, error.message().into())
136
    }
137
}
138

139
impl fmt::Display for Error {
140
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4✔
141
        match self {
4✔
142
            Error::InvalidPath(path) => write!(f, "The path {path:?} is invalid"),
1✔
UNCOV
143
            Error::IoError(path, error) =>
×
UNCOV
144
                write!(f, "I/O error involving the path {path:?}: {error}"),
×
UNCOV
145
            Error::NoFilename(path) =>
×
146
                write!(f, "The plugin path {path:?} has no filename part"),
×
147
            Error::SystemTimeError(error) => error.fmt(f),
×
148
            Error::NotUtf8(bytes) => write!(f, "Expected a UTF-8 string, got bytes {bytes:02X?}"),
1✔
149
            Error::DecodeError(bytes) => write!(f, "String could not be decoded from Windows-1252, bytes are {bytes:02X?}"),
×
150
            Error::EncodeError(string) => write!(f, "The string \"{string}\" could not be encoded to Windows-1252"),
×
151
            Error::PluginParsingError(path, err) => {
×
UNCOV
152
                write!(f, "An error was encountered while parsing the plugin at {path:?}: {err}")
×
153
            }
UNCOV
154
            Error::PluginNotFound(name) => {
×
155
                write!(f, "The plugin \"{name}\" is not in the load order")
×
156
            }
UNCOV
157
            Error::TooManyActivePlugins {light_count, normal_count } =>
×
158
                write!(f, "Maximum number of active plugins exceeded: there are {normal_count} active normal plugins and {light_count} active light plugins"),
×
159
            Error::DuplicatePlugin(name) =>
×
160
                write!(f, "The given plugin list contains more than one instance of \"{name}\""),
×
161
            Error::NonMasterBeforeMaster{ master, non_master} =>
×
162
                write!(f, "Attempted to load the non-master plugin \"{non_master}\" before the master plugin \"{master}\""),
×
163
            Error::GameMasterMustLoadFirst(name) =>
×
164
                write!(f, "The game's master file \"{name}\" must load first"),
×
165
            Error::InvalidEarlyLoadingPluginPosition{ name, pos, expected_pos } =>
×
166
                write!(f, "Attempted to load the early-loading plugin \"{name}\" at position {pos}, its expected position is {expected_pos}"),
×
167
            Error::ImplicitlyActivePlugin(name) =>
×
168
                write!(f, "The implicitly active plugin \"{name}\" cannot be deactivated"),
×
169
            Error::NoLocalAppData => {
170
                write!(f, "The game's local app data folder could not be detected")
1✔
171
            }
172
            Error::NoDocumentsPath => write!(f, "The user's Documents path could not be detected"),
×
173
            Error::UnrepresentedHoist { plugin, master } =>
×
174
                write!(f, "The plugin \"{plugin}\" is a master of \"{master}\", which will hoist it"),
×
175
            Error::InstalledPlugin(plugin) =>
×
176
                write!(f, "The plugin \"{plugin}\" is installed, so cannot be removed from the load order"),
×
177
            Error::IniParsingError {
UNCOV
178
                path,
×
179
                line,
×
UNCOV
180
                column,
×
181
                message,
×
182
            } => write!(f, "Failed to parse ini file at {path:?}, error at line {line}, column {column}: {message}"),
×
183
            Error::VdfParsingError(path, message) =>
×
184
                write!(f, "Failed to parse VDF file at {path:?}: {message}"),
×
185
            Error::SystemError(code, message) =>
1✔
186
                write!(f, "Error returned by the operating system, code {code}: {message:?}"),
1✔
187
        }
188
    }
4✔
189
}
190

191
impl error::Error for Error {
UNCOV
192
    fn cause(&self) -> Option<&dyn error::Error> {
×
UNCOV
193
        match *self {
×
UNCOV
194
            Error::IoError(_, ref x) => Some(x),
×
UNCOV
195
            Error::SystemTimeError(ref x) => Some(x),
×
196
            Error::PluginParsingError(_, ref x) => Some(x.as_ref()),
×
197
            _ => None,
×
198
        }
199
    }
×
200
}
201

202
#[cfg(test)]
203
mod tests {
204
    use super::*;
205

206
    #[test]
207
    fn game_id_should_map_to_libespm_id_correctly() {
1✔
208
        assert_eq!(
1✔
209
            esplugin::GameId::Morrowind,
1✔
210
            GameId::Morrowind.to_esplugin_id()
1✔
211
        );
1✔
212
        assert_eq!(
1✔
213
            esplugin::GameId::Oblivion,
1✔
214
            GameId::Oblivion.to_esplugin_id()
1✔
215
        );
1✔
216
        assert_eq!(esplugin::GameId::Skyrim, GameId::Skyrim.to_esplugin_id());
1✔
217
        assert_eq!(
1✔
218
            esplugin::GameId::SkyrimSE,
1✔
219
            GameId::SkyrimSE.to_esplugin_id()
1✔
220
        );
1✔
221
        assert_eq!(
1✔
222
            esplugin::GameId::SkyrimSE,
1✔
223
            GameId::SkyrimVR.to_esplugin_id()
1✔
224
        );
1✔
225
        assert_eq!(
1✔
226
            esplugin::GameId::Fallout3,
1✔
227
            GameId::Fallout3.to_esplugin_id()
1✔
228
        );
1✔
229
        assert_eq!(
1✔
230
            esplugin::GameId::FalloutNV,
1✔
231
            GameId::FalloutNV.to_esplugin_id()
1✔
232
        );
1✔
233
        assert_eq!(
1✔
234
            esplugin::GameId::Fallout4,
1✔
235
            GameId::Fallout4.to_esplugin_id()
1✔
236
        );
1✔
237
        assert_eq!(
1✔
238
            esplugin::GameId::Fallout4,
1✔
239
            GameId::Fallout4VR.to_esplugin_id()
1✔
240
        );
1✔
241
        assert_eq!(
1✔
242
            esplugin::GameId::Starfield,
1✔
243
            GameId::Starfield.to_esplugin_id()
1✔
244
        );
1✔
245
    }
1✔
246

247
    #[test]
248
    fn game_id_supports_light_plugins_should_be_false_until_fallout_4() {
1✔
249
        assert!(!GameId::Morrowind.supports_light_plugins());
1✔
250
        assert!(!GameId::Oblivion.supports_light_plugins());
1✔
251
        assert!(!GameId::Skyrim.supports_light_plugins());
1✔
252
        assert!(GameId::SkyrimSE.supports_light_plugins());
1✔
253
        assert!(GameId::SkyrimVR.supports_light_plugins());
1✔
254
        assert!(!GameId::Fallout3.supports_light_plugins());
1✔
255
        assert!(!GameId::FalloutNV.supports_light_plugins());
1✔
256
        assert!(GameId::Fallout4.supports_light_plugins());
1✔
257
        assert!(GameId::Fallout4VR.supports_light_plugins());
1✔
258
        assert!(GameId::Starfield.supports_light_plugins());
1✔
259
    }
1✔
260

261
    #[test]
262
    fn error_display_should_print_double_quoted_paths() {
1✔
263
        let string = format!("{}", Error::InvalidPath(PathBuf::from("foo")));
1✔
264

1✔
265
        assert_eq!("The path \"foo\" is invalid", string);
1✔
266
    }
1✔
267

268
    #[test]
269
    fn error_display_should_print_byte_vec_as_hex_array() {
1✔
270
        let string = format!("{}", Error::NotUtf8(vec![0x2f, 0x47, 0x03]));
1✔
271

1✔
272
        assert_eq!("Expected a UTF-8 string, got bytes [2F, 47, 03]", string);
1✔
273
    }
1✔
274

275
    #[test]
276
    fn error_display_should_print_os_string_as_quoted_string() {
1✔
277
        let string = format!("{}", Error::SystemError(1, OsString::from("foo")));
1✔
278

1✔
279
        assert_eq!(
1✔
280
            "Error returned by the operating system, code 1: \"foo\"",
1✔
281
            string
1✔
282
        );
1✔
283
    }
1✔
284
}
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