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

loot / loot-condition-interpreter / 14679793593

26 Apr 2025 09:10AM UTC coverage: 91.6% (+0.02%) from 91.583%
14679793593

push

github

Ortham
Deny a lot of extra lints and fix their errors

337 of 376 new or added lines in 10 files covered. (89.63%)

111 existing lines in 7 files now uncovered.

4907 of 5357 relevant lines covered (91.6%)

15.84 hits per line

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

99.54
/src/function/mod.rs
1
use std::fmt;
2
use std::hash::{Hash, Hasher};
3
use std::mem::discriminant;
4
use std::path::PathBuf;
5

6
use regex::Regex;
7
use unicase::eq;
8

9
pub(crate) mod eval;
10
pub(crate) mod parse;
11
mod path;
12
mod version;
13

14
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
15
pub enum ComparisonOperator {
16
    Equal,
17
    NotEqual,
18
    LessThan,
19
    GreaterThan,
20
    LessThanOrEqual,
21
    GreaterThanOrEqual,
22
}
23

24
impl fmt::Display for ComparisonOperator {
25
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3✔
26
        match self {
3✔
27
            Self::Equal => write!(f, "=="),
3✔
NEW
28
            Self::NotEqual => write!(f, "!="),
×
NEW
29
            Self::LessThan => write!(f, "<"),
×
NEW
30
            Self::GreaterThan => write!(f, ">"),
×
NEW
31
            Self::LessThanOrEqual => write!(f, "<="),
×
NEW
32
            Self::GreaterThanOrEqual => write!(f, ">="),
×
33
        }
34
    }
3✔
35
}
36

37
#[derive(Clone, Debug)]
38
pub enum Function {
39
    FilePath(PathBuf),
40
    FileRegex(PathBuf, Regex),
41
    FileSize(PathBuf, u64),
42
    Readable(PathBuf),
43
    IsExecutable(PathBuf),
44
    ActivePath(PathBuf),
45
    ActiveRegex(Regex),
46
    IsMaster(PathBuf),
47
    Many(PathBuf, Regex),
48
    ManyActive(Regex),
49
    Checksum(PathBuf, u32),
50
    Version(PathBuf, String, ComparisonOperator),
51
    ProductVersion(PathBuf, String, ComparisonOperator),
52
    FilenameVersion(PathBuf, Regex, String, ComparisonOperator),
53
    DescriptionContains(PathBuf, Regex),
54
}
55

56
impl fmt::Display for Function {
57
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25✔
58
        match self {
25✔
59
            Self::FilePath(p) => write!(f, "file(\"{}\")", p.display()),
11✔
60
            Self::FileRegex(p, r) => write!(f, "file(\"{}/{}\")", p.display(), r),
1✔
61
            Self::FileSize(p, s) => write!(f, "file_size(\"{}\", {})", p.display(), s),
1✔
62
            Self::Readable(p) => write!(f, "readable(\"{}\")", p.display()),
1✔
63
            Self::IsExecutable(p) => write!(f, "is_executable(\"{}\")", p.display()),
1✔
64
            Self::ActivePath(p) => write!(f, "active(\"{}\")", p.display()),
1✔
65
            Self::ActiveRegex(r) => write!(f, "active(\"{r}\")"),
1✔
66
            Self::IsMaster(p) => write!(f, "is_master(\"{}\")", p.display()),
1✔
67
            Self::Many(p, r) => write!(f, "many(\"{}/{}\")", p.display(), r),
1✔
68
            Self::ManyActive(r) => write!(f, "many_active(\"{r}\")"),
1✔
69
            Self::Checksum(p, c) => write!(f, "checksum(\"{}\", {:02X})", p.display(), c),
1✔
70
            Self::Version(p, v, c) => write!(f, "version(\"{}\", \"{}\", {})", p.display(), v, c),
1✔
71
            Self::ProductVersion(p, v, c) => {
1✔
72
                write!(f, "product_version(\"{}\", \"{}\", {})", p.display(), v, c)
1✔
73
            }
74
            Self::FilenameVersion(path, regex, version, comparator) => {
1✔
75
                write!(
1✔
76
                    f,
1✔
77
                    "filename_version(\"{}/{}\", \"{}\", {})",
1✔
78
                    path.display(),
1✔
79
                    regex,
1✔
80
                    version,
1✔
81
                    comparator
1✔
82
                )
1✔
83
            }
84
            Self::DescriptionContains(p, r) => {
1✔
85
                write!(f, "description_contains(\"{}\", \"{}\")", p.display(), r)
1✔
86
            }
87
        }
88
    }
25✔
89
}
90

91
impl PartialEq for Function {
92
    fn eq(&self, other: &Function) -> bool {
71✔
93
        match (self, other) {
71✔
94
            (Self::FilePath(p1), Self::FilePath(p2))
6✔
95
            | (Self::Readable(p1), Self::Readable(p2))
3✔
96
            | (Self::IsExecutable(p1), Self::IsExecutable(p2))
3✔
97
            | (Self::ActivePath(p1), Self::ActivePath(p2))
3✔
98
            | (Self::IsMaster(p1), Self::IsMaster(p2)) => {
3✔
99
                eq(&p1.to_string_lossy(), &p2.to_string_lossy())
18✔
100
            }
101
            (Self::FileRegex(p1, r1), Self::FileRegex(p2, r2))
4✔
102
            | (Self::Many(p1, r1), Self::Many(p2, r2))
4✔
103
            | (Self::DescriptionContains(p1, r1), Self::DescriptionContains(p2, r2)) => {
4✔
104
                eq(r1.as_str(), r2.as_str()) && eq(&p1.to_string_lossy(), &p2.to_string_lossy())
12✔
105
            }
106
            (Self::FileSize(p1, s1), Self::FileSize(p2, s2)) => {
4✔
107
                s1 == s2 && eq(&p1.to_string_lossy(), &p2.to_string_lossy())
4✔
108
            }
109
            (Self::ActiveRegex(r1), Self::ActiveRegex(r2))
3✔
110
            | (Self::ManyActive(r1), Self::ManyActive(r2)) => eq(r1.as_str(), r2.as_str()),
6✔
111
            (Self::Checksum(p1, c1), Self::Checksum(p2, c2)) => {
4✔
112
                c1 == c2 && eq(&p1.to_string_lossy(), &p2.to_string_lossy())
4✔
113
            }
114
            (Self::Version(p1, v1, c1), Self::Version(p2, v2, c2))
5✔
115
            | (Self::ProductVersion(p1, v1, c1), Self::ProductVersion(p2, v2, c2)) => {
5✔
116
                c1 == c2 && eq(&v1, &v2) && eq(&p1.to_string_lossy(), &p2.to_string_lossy())
10✔
117
            }
118
            (Self::FilenameVersion(p1, r1, v1, c1), Self::FilenameVersion(p2, r2, v2, c2)) => {
6✔
119
                c1 == c2
6✔
120
                    && eq(&v1, &v2)
5✔
121
                    && eq(r1.as_str(), r2.as_str())
4✔
122
                    && eq(&p1.to_string_lossy(), &p2.to_string_lossy())
3✔
123
            }
124
            _ => false,
11✔
125
        }
126
    }
71✔
127
}
128

129
impl Eq for Function {}
130

131
impl Hash for Function {
132
    fn hash<H: Hasher>(&self, state: &mut H) {
258✔
133
        match self {
258✔
134
            Self::FilePath(p)
33✔
135
            | Self::Readable(p)
17✔
136
            | Self::IsExecutable(p)
13✔
137
            | Self::ActivePath(p)
9✔
138
            | Self::IsMaster(p) => {
86✔
139
                p.to_string_lossy().to_lowercase().hash(state);
86✔
140
            }
86✔
141
            Self::FileRegex(p, r) | Self::Many(p, r) | Self::DescriptionContains(p, r) => {
44✔
142
                p.to_string_lossy().to_lowercase().hash(state);
44✔
143
                r.as_str().to_lowercase().hash(state);
44✔
144
            }
44✔
145
            Self::FileSize(p, s) => {
13✔
146
                p.to_string_lossy().to_lowercase().hash(state);
13✔
147
                s.hash(state);
13✔
148
            }
13✔
149
            Self::ActiveRegex(r) | Self::ManyActive(r) => {
14✔
150
                r.as_str().to_lowercase().hash(state);
14✔
151
            }
14✔
152
            Self::Checksum(p, c) => {
8✔
153
                p.to_string_lossy().to_lowercase().hash(state);
8✔
154
                c.hash(state);
8✔
155
            }
8✔
156
            Self::Version(p, v, c) | Self::ProductVersion(p, v, c) => {
64✔
157
                p.to_string_lossy().to_lowercase().hash(state);
64✔
158
                v.to_lowercase().hash(state);
64✔
159
                c.hash(state);
64✔
160
            }
64✔
161
            Self::FilenameVersion(p, r, v, c) => {
29✔
162
                p.to_string_lossy().to_lowercase().hash(state);
29✔
163
                r.as_str().to_lowercase().hash(state);
29✔
164
                v.to_lowercase().hash(state);
29✔
165
                c.hash(state);
29✔
166
            }
29✔
167
        }
168

169
        discriminant(self).hash(state);
258✔
170
    }
258✔
171
}
172

173
#[cfg(test)]
174
mod tests {
175
    use super::*;
176

177
    const LOWERCASE_NON_ASCII: &str = "\u{20ac}\u{192}.";
178
    const UPPERCASE_NON_ASCII: &str = "\u{20ac}\u{191}.";
179

180
    fn regex(string: &str) -> Regex {
114✔
181
        Regex::new(string).unwrap()
114✔
182
    }
114✔
183

184
    mod fmt {
185
        use super::*;
186

187
        #[test]
188
        fn function_fmt_for_file_path_should_format_correctly() {
1✔
189
            let function = Function::FilePath("subdir/Blank.esm".into());
1✔
190

1✔
191
            assert_eq!("file(\"subdir/Blank.esm\")", &format!("{function}"));
1✔
192
        }
1✔
193

194
        #[test]
195
        fn function_fmt_for_file_regex_should_format_correctly() {
1✔
196
            let function = Function::FileRegex("subdir".into(), regex("Blank.*"));
1✔
197

1✔
198
            assert_eq!("file(\"subdir/Blank.*\")", &format!("{function}"));
1✔
199
        }
1✔
200

201
        #[test]
202
        fn function_fmt_for_file_size_should_format_correctly() {
1✔
203
            let function = Function::FileSize("subdir/Blank.esm".into(), 12_345_678);
1✔
204

1✔
205
            assert_eq!(
1✔
206
                "file_size(\"subdir/Blank.esm\", 12345678)",
1✔
207
                &format!("{function}")
1✔
208
            );
1✔
209
        }
1✔
210

211
        #[test]
212
        fn function_fmt_for_readable_should_format_correctly() {
1✔
213
            let function = Function::Readable("subdir/Blank.esm".into());
1✔
214

1✔
215
            assert_eq!("readable(\"subdir/Blank.esm\")", &format!("{function}"));
1✔
216
        }
1✔
217

218
        #[test]
219
        fn function_fmt_for_is_executable_should_format_correctly() {
1✔
220
            let function = Function::IsExecutable("subdir/Blank.esm".into());
1✔
221

1✔
222
            assert_eq!(
1✔
223
                "is_executable(\"subdir/Blank.esm\")",
1✔
224
                &format!("{function}")
1✔
225
            );
1✔
226
        }
1✔
227

228
        #[test]
229
        fn function_fmt_for_active_path_should_format_correctly() {
1✔
230
            let function = Function::ActivePath("Blank.esm".into());
1✔
231

1✔
232
            assert_eq!("active(\"Blank.esm\")", &format!("{function}"));
1✔
233
        }
1✔
234

235
        #[test]
236
        fn function_fmt_for_active_regex_should_format_correctly() {
1✔
237
            let function = Function::ActiveRegex(regex("Blank.*"));
1✔
238

1✔
239
            assert_eq!("active(\"Blank.*\")", &format!("{function}"));
1✔
240
        }
1✔
241

242
        #[test]
243
        fn function_fmt_for_is_master_should_format_correctly() {
1✔
244
            let function = Function::IsMaster("Blank.esm".into());
1✔
245

1✔
246
            assert_eq!("is_master(\"Blank.esm\")", &format!("{function}"));
1✔
247
        }
1✔
248

249
        #[test]
250
        fn function_fmt_for_many_should_format_correctly() {
1✔
251
            let function = Function::Many("subdir".into(), regex("Blank.*"));
1✔
252

1✔
253
            assert_eq!("many(\"subdir/Blank.*\")", &format!("{function}"));
1✔
254
        }
1✔
255

256
        #[test]
257
        fn function_fmt_for_many_active_should_format_correctly() {
1✔
258
            let function = Function::ManyActive(regex("Blank.*"));
1✔
259

1✔
260
            assert_eq!("many_active(\"Blank.*\")", &format!("{function}"));
1✔
261
        }
1✔
262

263
        #[test]
264
        fn function_fmt_for_checksum_should_format_correctly() {
1✔
265
            let function = Function::Checksum("subdir/Blank.esm".into(), 0xDEAD_BEEF);
1✔
266

1✔
267
            assert_eq!(
1✔
268
                "checksum(\"subdir/Blank.esm\", DEADBEEF)",
1✔
269
                &format!("{function}")
1✔
270
            );
1✔
271
        }
1✔
272

273
        #[test]
274
        fn function_fmt_for_version_should_format_correctly() {
1✔
275
            let function = Function::Version(
1✔
276
                "subdir/Blank.esm".into(),
1✔
277
                "1.2a".into(),
1✔
278
                ComparisonOperator::Equal,
1✔
279
            );
1✔
280

1✔
281
            assert_eq!(
1✔
282
                "version(\"subdir/Blank.esm\", \"1.2a\", ==)",
1✔
283
                &format!("{function}")
1✔
284
            );
1✔
285
        }
1✔
286

287
        #[test]
288
        fn function_fmt_for_product_version_should_format_correctly() {
1✔
289
            let function = Function::ProductVersion(
1✔
290
                "../TESV.exe".into(),
1✔
291
                "1.2a".into(),
1✔
292
                ComparisonOperator::Equal,
1✔
293
            );
1✔
294

1✔
295
            assert_eq!(
1✔
296
                "product_version(\"../TESV.exe\", \"1.2a\", ==)",
1✔
297
                &format!("{function}")
1✔
298
            );
1✔
299
        }
1✔
300

301
        #[test]
302
        fn function_fmt_for_filename_version_should_format_correctly() {
1✔
303
            let function = Function::FilenameVersion(
1✔
304
                "subdir".into(),
1✔
305
                regex(r"filename (\d+(?:[_.-]?\d+)*[a-z]?)\.esp"),
1✔
306
                "1.2a".into(),
1✔
307
                ComparisonOperator::Equal,
1✔
308
            );
1✔
309

1✔
310
            assert_eq!(
1✔
311
                "filename_version(\"subdir/filename (\\d+(?:[_.-]?\\d+)*[a-z]?)\\.esp\", \"1.2a\", ==)",
1✔
312
                &format!("{function}")
1✔
313
            );
1✔
314
        }
1✔
315

316
        #[test]
317
        fn function_fmt_for_description_contains_should_format_correctly() {
1✔
318
            let function =
1✔
319
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII));
1✔
320

1✔
321
            assert_eq!(
1✔
322
                &format!("description_contains(\"Blank.esp\", \"{LOWERCASE_NON_ASCII}\")"),
1✔
323
                &format!("{function}")
1✔
324
            );
1✔
325
        }
1✔
326
    }
327

328
    mod eq {
329
        use super::*;
330

331
        #[test]
332
        fn function_eq_for_file_path_should_check_pathbuf() {
1✔
333
            assert_eq!(
1✔
334
                Function::FilePath("Blank.esm".into()),
1✔
335
                Function::FilePath("Blank.esm".into())
1✔
336
            );
1✔
337

338
            assert_ne!(
1✔
339
                Function::FilePath("Blank.esp".into()),
1✔
340
                Function::FilePath("Blank.esm".into())
1✔
341
            );
1✔
342
        }
1✔
343

344
        #[test]
345
        fn function_eq_for_file_path_should_be_case_insensitive_on_pathbuf() {
1✔
346
            assert_eq!(
1✔
347
                Function::FilePath("Blank.esm".into()),
1✔
348
                Function::FilePath("blank.esm".into())
1✔
349
            );
1✔
350
        }
1✔
351

352
        #[test]
353
        fn function_eq_for_file_regex_should_check_pathbuf_and_regex() {
1✔
354
            assert_eq!(
1✔
355
                Function::FileRegex("subdir".into(), regex("blank.*")),
1✔
356
                Function::FileRegex("subdir".into(), regex("blank.*"))
1✔
357
            );
1✔
358

359
            assert_ne!(
1✔
360
                Function::FileRegex("subdir".into(), regex("blank.*")),
1✔
361
                Function::FileRegex("other".into(), regex("blank.*"))
1✔
362
            );
1✔
363
            assert_ne!(
1✔
364
                Function::FileRegex("subdir".into(), regex("blank.*")),
1✔
365
                Function::FileRegex("subdir".into(), regex(".*"))
1✔
366
            );
1✔
367
        }
1✔
368

369
        #[test]
370
        fn function_eq_for_file_regex_should_be_case_insensitive_on_pathbuf_and_regex() {
1✔
371
            assert_eq!(
1✔
372
                Function::FileRegex("subdir".into(), regex("blank.*")),
1✔
373
                Function::FileRegex("Subdir".into(), regex("Blank.*"))
1✔
374
            );
1✔
375
        }
1✔
376

377
        #[test]
378
        fn function_eq_for_file_size_should_check_pathbuf_and_size() {
1✔
379
            assert_eq!(
1✔
380
                Function::FileSize("subdir".into(), 1),
1✔
381
                Function::FileSize("subdir".into(), 1)
1✔
382
            );
1✔
383

384
            assert_ne!(
1✔
385
                Function::FileSize("subdir".into(), 1),
1✔
386
                Function::FileSize("other".into(), 1)
1✔
387
            );
1✔
388
            assert_ne!(
1✔
389
                Function::FileSize("subdir".into(), 1),
1✔
390
                Function::FileSize("subdir".into(), 2)
1✔
391
            );
1✔
392
        }
1✔
393

394
        #[test]
395
        fn function_eq_for_file_size_should_be_case_insensitive_on_pathbuf() {
1✔
396
            assert_eq!(
1✔
397
                Function::FileSize("subdir".into(), 1),
1✔
398
                Function::FileSize("Subdir".into(), 1)
1✔
399
            );
1✔
400
        }
1✔
401

402
        #[test]
403
        fn function_eq_for_readable_should_check_pathbuf() {
1✔
404
            assert_eq!(
1✔
405
                Function::Readable("Blank.esm".into()),
1✔
406
                Function::Readable("Blank.esm".into())
1✔
407
            );
1✔
408

409
            assert_ne!(
1✔
410
                Function::Readable("Blank.esp".into()),
1✔
411
                Function::Readable("Blank.esm".into())
1✔
412
            );
1✔
413
        }
1✔
414

415
        #[test]
416
        fn function_eq_for_readable_should_be_case_insensitive_on_pathbuf() {
1✔
417
            assert_eq!(
1✔
418
                Function::Readable("Blank.esm".into()),
1✔
419
                Function::Readable("blank.esm".into())
1✔
420
            );
1✔
421
        }
1✔
422

423
        #[test]
424
        fn function_eq_for_readable_should_not_be_equal_to_file_path_with_same_pathbuf() {
1✔
425
            assert_ne!(
1✔
426
                Function::Readable("Blank.esm".into()),
1✔
427
                Function::FilePath("Blank.esm".into())
1✔
428
            );
1✔
429
        }
1✔
430

431
        #[test]
432
        fn function_eq_for_is_executable_should_check_pathbuf() {
1✔
433
            assert_eq!(
1✔
434
                Function::IsExecutable("Blank.esm".into()),
1✔
435
                Function::IsExecutable("Blank.esm".into())
1✔
436
            );
1✔
437

438
            assert_ne!(
1✔
439
                Function::IsExecutable("Blank.esp".into()),
1✔
440
                Function::IsExecutable("Blank.esm".into())
1✔
441
            );
1✔
442
        }
1✔
443

444
        #[test]
445
        fn function_eq_for_is_executable_should_be_case_insensitive_on_pathbuf() {
1✔
446
            assert_eq!(
1✔
447
                Function::IsExecutable("Blank.esm".into()),
1✔
448
                Function::IsExecutable("blank.esm".into())
1✔
449
            );
1✔
450
        }
1✔
451

452
        #[test]
453
        fn function_eq_for_is_executable_should_not_be_equal_to_file_path_or_is_executable_with_same_pathbuf(
1✔
454
        ) {
1✔
455
            assert_ne!(
1✔
456
                Function::IsExecutable("Blank.esm".into()),
1✔
457
                Function::FilePath("Blank.esm".into())
1✔
458
            );
1✔
459
            assert_ne!(
1✔
460
                Function::IsExecutable("Blank.esm".into()),
1✔
461
                Function::Readable("Blank.esm".into())
1✔
462
            );
1✔
463
        }
1✔
464

465
        #[test]
466
        fn function_eq_for_active_path_should_check_pathbuf() {
1✔
467
            assert_eq!(
1✔
468
                Function::ActivePath("Blank.esm".into()),
1✔
469
                Function::ActivePath("Blank.esm".into())
1✔
470
            );
1✔
471

472
            assert_ne!(
1✔
473
                Function::ActivePath("Blank.esp".into()),
1✔
474
                Function::ActivePath("Blank.esm".into())
1✔
475
            );
1✔
476
        }
1✔
477

478
        #[test]
479
        fn function_eq_for_active_path_should_be_case_insensitive_on_pathbuf() {
1✔
480
            assert_eq!(
1✔
481
                Function::ActivePath("Blank.esm".into()),
1✔
482
                Function::ActivePath("blank.esm".into())
1✔
483
            );
1✔
484
        }
1✔
485

486
        #[test]
487
        fn function_eq_for_active_path_should_not_be_equal_to_file_path_with_same_pathbuf() {
1✔
488
            assert_ne!(
1✔
489
                Function::ActivePath("Blank.esm".into()),
1✔
490
                Function::FilePath("Blank.esm".into())
1✔
491
            );
1✔
492
        }
1✔
493

494
        #[test]
495
        fn function_eq_for_active_path_should_not_be_equal_to_readable_with_same_pathbuf() {
1✔
496
            assert_ne!(
1✔
497
                Function::ActivePath("Blank.esm".into()),
1✔
498
                Function::Readable("Blank.esm".into())
1✔
499
            );
1✔
500
        }
1✔
501

502
        #[test]
503
        fn function_eq_for_active_regex_should_check_regex() {
1✔
504
            assert_eq!(
1✔
505
                Function::ActiveRegex(regex("blank.*")),
1✔
506
                Function::ActiveRegex(regex("blank.*"))
1✔
507
            );
1✔
508

509
            assert_ne!(
1✔
510
                Function::ActiveRegex(regex("blank.*")),
1✔
511
                Function::ActiveRegex(regex(".*"))
1✔
512
            );
1✔
513
        }
1✔
514

515
        #[test]
516
        fn function_eq_for_active_regex_should_be_case_insensitive_on_regex() {
1✔
517
            assert_eq!(
1✔
518
                Function::ActiveRegex(regex("blank.*")),
1✔
519
                Function::ActiveRegex(regex("Blank.*"))
1✔
520
            );
1✔
521
        }
1✔
522

523
        #[test]
524
        fn function_eq_for_is_master_should_check_pathbuf() {
1✔
525
            assert_eq!(
1✔
526
                Function::IsMaster("Blank.esm".into()),
1✔
527
                Function::IsMaster("Blank.esm".into())
1✔
528
            );
1✔
529

530
            assert_ne!(
1✔
531
                Function::IsMaster("Blank.esp".into()),
1✔
532
                Function::IsMaster("Blank.esm".into())
1✔
533
            );
1✔
534
        }
1✔
535

536
        #[test]
537
        fn function_eq_for_is_master_should_be_case_insensitive_on_pathbuf() {
1✔
538
            assert_eq!(
1✔
539
                Function::IsMaster("Blank.esm".into()),
1✔
540
                Function::IsMaster("blank.esm".into())
1✔
541
            );
1✔
542
        }
1✔
543

544
        #[test]
545
        fn function_eq_for_is_master_should_not_be_equal_to_file_path_with_same_pathbuf() {
1✔
546
            assert_ne!(
1✔
547
                Function::IsMaster("Blank.esm".into()),
1✔
548
                Function::FilePath("Blank.esm".into())
1✔
549
            );
1✔
550
        }
1✔
551

552
        #[test]
553
        fn function_eq_for_is_master_should_not_be_equal_to_readable_with_same_pathbuf() {
1✔
554
            assert_ne!(
1✔
555
                Function::IsMaster("Blank.esm".into()),
1✔
556
                Function::Readable("Blank.esm".into())
1✔
557
            );
1✔
558
        }
1✔
559

560
        #[test]
561
        fn function_eq_for_is_master_should_not_be_equal_to_active_path_with_same_pathbuf() {
1✔
562
            assert_ne!(
1✔
563
                Function::IsMaster("Blank.esm".into()),
1✔
564
                Function::ActivePath("Blank.esm".into())
1✔
565
            );
1✔
566
        }
1✔
567

568
        #[test]
569
        fn function_eq_for_many_should_check_pathbuf_and_regex() {
1✔
570
            assert_eq!(
1✔
571
                Function::Many("subdir".into(), regex("blank.*")),
1✔
572
                Function::Many("subdir".into(), regex("blank.*"))
1✔
573
            );
1✔
574

575
            assert_ne!(
1✔
576
                Function::Many("subdir".into(), regex("blank.*")),
1✔
577
                Function::Many("subdir".into(), regex(".*"))
1✔
578
            );
1✔
579
            assert_ne!(
1✔
580
                Function::Many("subdir".into(), regex("blank.*")),
1✔
581
                Function::Many("other".into(), regex("blank.*"))
1✔
582
            );
1✔
583
        }
1✔
584

585
        #[test]
586
        fn function_eq_for_many_should_be_case_insensitive_on_pathbuf_and_regex() {
1✔
587
            assert_eq!(
1✔
588
                Function::Many("subdir".into(), regex("blank.*")),
1✔
589
                Function::Many("Subdir".into(), regex("Blank.*"))
1✔
590
            );
1✔
591
        }
1✔
592

593
        #[test]
594
        fn function_eq_many_should_not_be_equal_to_file_regex_with_same_pathbuf_and_regex() {
1✔
595
            assert_ne!(
1✔
596
                Function::Many("subdir".into(), regex("blank.*")),
1✔
597
                Function::FileRegex("subdir".into(), regex("blank.*"))
1✔
598
            );
1✔
599
        }
1✔
600

601
        #[test]
602
        fn function_eq_for_many_active_should_check_regex() {
1✔
603
            assert_eq!(
1✔
604
                Function::ManyActive(regex("blank.*")),
1✔
605
                Function::ManyActive(regex("blank.*"))
1✔
606
            );
1✔
607

608
            assert_ne!(
1✔
609
                Function::ManyActive(regex("blank.*")),
1✔
610
                Function::ManyActive(regex(".*"))
1✔
611
            );
1✔
612
        }
1✔
613

614
        #[test]
615
        fn function_eq_for_many_active_should_be_case_insensitive_on_regex() {
1✔
616
            assert_eq!(
1✔
617
                Function::ManyActive(regex("blank.*")),
1✔
618
                Function::ManyActive(regex("Blank.*"))
1✔
619
            );
1✔
620
        }
1✔
621

622
        #[test]
623
        fn function_eq_many_active_should_not_be_equal_to_active_regex_with_same_regex() {
1✔
624
            assert_ne!(
1✔
625
                Function::ManyActive(regex("blank.*")),
1✔
626
                Function::ActiveRegex(regex("blank.*"))
1✔
627
            );
1✔
628
        }
1✔
629

630
        #[test]
631
        fn function_eq_for_checksum_should_check_pathbuf_and_crc() {
1✔
632
            assert_eq!(
1✔
633
                Function::Checksum("Blank.esm".into(), 1),
1✔
634
                Function::Checksum("Blank.esm".into(), 1)
1✔
635
            );
1✔
636

637
            assert_ne!(
1✔
638
                Function::Checksum("Blank.esm".into(), 1),
1✔
639
                Function::Checksum("Blank.esm".into(), 2)
1✔
640
            );
1✔
641
            assert_ne!(
1✔
642
                Function::Checksum("Blank.esm".into(), 1),
1✔
643
                Function::Checksum("Blank.esp".into(), 1)
1✔
644
            );
1✔
645
        }
1✔
646

647
        #[test]
648
        fn function_eq_for_checksum_should_be_case_insensitive_on_pathbuf() {
1✔
649
            assert_eq!(
1✔
650
                Function::Checksum("Blank.esm".into(), 1),
1✔
651
                Function::Checksum("blank.esm".into(), 1)
1✔
652
            );
1✔
653
        }
1✔
654

655
        #[test]
656
        fn function_eq_for_version_should_check_pathbuf_version_and_comparator() {
1✔
657
            assert_eq!(
1✔
658
                Function::Version("Blank.esm".into(), "1".into(), ComparisonOperator::Equal),
1✔
659
                Function::Version("Blank.esm".into(), "1".into(), ComparisonOperator::Equal)
1✔
660
            );
1✔
661

662
            assert_ne!(
1✔
663
                Function::Version("Blank.esm".into(), "1".into(), ComparisonOperator::Equal),
1✔
664
                Function::Version("Blank.esp".into(), "1".into(), ComparisonOperator::Equal)
1✔
665
            );
1✔
666
            assert_ne!(
1✔
667
                Function::Version("Blank.esm".into(), "1".into(), ComparisonOperator::Equal),
1✔
668
                Function::Version("Blank.esm".into(), "2".into(), ComparisonOperator::Equal)
1✔
669
            );
1✔
670
            assert_ne!(
1✔
671
                Function::Version("Blank.esm".into(), "1".into(), ComparisonOperator::Equal),
1✔
672
                Function::Version("Blank.esm".into(), "1".into(), ComparisonOperator::NotEqual)
1✔
673
            );
1✔
674
        }
1✔
675

676
        #[test]
677
        fn function_eq_for_version_should_be_case_insensitive_on_pathbuf_and_version() {
1✔
678
            assert_eq!(
1✔
679
                Function::Version("Blank.esm".into(), "A".into(), ComparisonOperator::Equal),
1✔
680
                Function::Version("blank.esm".into(), "a".into(), ComparisonOperator::Equal)
1✔
681
            );
1✔
682
        }
1✔
683

684
        #[test]
685
        fn function_eq_for_product_version_should_check_pathbuf_version_and_comparator() {
1✔
686
            assert_eq!(
1✔
687
                Function::ProductVersion("Blank.esm".into(), "1".into(), ComparisonOperator::Equal),
1✔
688
                Function::ProductVersion("Blank.esm".into(), "1".into(), ComparisonOperator::Equal)
1✔
689
            );
1✔
690

691
            assert_ne!(
1✔
692
                Function::ProductVersion("Blank.esm".into(), "1".into(), ComparisonOperator::Equal),
1✔
693
                Function::ProductVersion("Blank.esp".into(), "1".into(), ComparisonOperator::Equal)
1✔
694
            );
1✔
695
            assert_ne!(
1✔
696
                Function::ProductVersion("Blank.esm".into(), "1".into(), ComparisonOperator::Equal),
1✔
697
                Function::ProductVersion("Blank.esm".into(), "2".into(), ComparisonOperator::Equal)
1✔
698
            );
1✔
699
            assert_ne!(
1✔
700
                Function::ProductVersion("Blank.esm".into(), "1".into(), ComparisonOperator::Equal),
1✔
701
                Function::ProductVersion(
1✔
702
                    "Blank.esm".into(),
1✔
703
                    "1".into(),
1✔
704
                    ComparisonOperator::NotEqual
1✔
705
                )
1✔
706
            );
1✔
707
        }
1✔
708

709
        #[test]
710
        fn function_eq_for_product_version_should_be_case_insensitive_on_pathbuf_and_version() {
1✔
711
            assert_eq!(
1✔
712
                Function::ProductVersion("Blank.esm".into(), "A".into(), ComparisonOperator::Equal),
1✔
713
                Function::ProductVersion("blank.esm".into(), "a".into(), ComparisonOperator::Equal)
1✔
714
            );
1✔
715
        }
1✔
716

717
        #[test]
718
        fn function_eq_for_filename_version_should_check_pathbuf_regex_version_and_comparator() {
1✔
719
            assert_eq!(
1✔
720
                Function::FilenameVersion(
1✔
721
                    "subdir".into(),
1✔
722
                    regex("Blank\\.esm"),
1✔
723
                    "1".into(),
1✔
724
                    ComparisonOperator::Equal
1✔
725
                ),
1✔
726
                Function::FilenameVersion(
1✔
727
                    "subdir".into(),
1✔
728
                    regex("Blank\\.esm"),
1✔
729
                    "1".into(),
1✔
730
                    ComparisonOperator::Equal
1✔
731
                )
1✔
732
            );
1✔
733

734
            assert_ne!(
1✔
735
                Function::FilenameVersion(
1✔
736
                    "subdir1".into(),
1✔
737
                    regex("Blank\\.esm"),
1✔
738
                    "1".into(),
1✔
739
                    ComparisonOperator::Equal
1✔
740
                ),
1✔
741
                Function::FilenameVersion(
1✔
742
                    "subdir2".into(),
1✔
743
                    regex("Blank\\.esm"),
1✔
744
                    "1".into(),
1✔
745
                    ComparisonOperator::Equal
1✔
746
                )
1✔
747
            );
1✔
748
            assert_ne!(
1✔
749
                Function::FilenameVersion(
1✔
750
                    "subdir".into(),
1✔
751
                    regex("Blank\\.esm"),
1✔
752
                    "1".into(),
1✔
753
                    ComparisonOperator::Equal
1✔
754
                ),
1✔
755
                Function::FilenameVersion(
1✔
756
                    "subdir".into(),
1✔
757
                    regex("Blank.esp"),
1✔
758
                    "1".into(),
1✔
759
                    ComparisonOperator::Equal
1✔
760
                )
1✔
761
            );
1✔
762
            assert_ne!(
1✔
763
                Function::FilenameVersion(
1✔
764
                    "subdir".into(),
1✔
765
                    regex("Blank\\.esm"),
1✔
766
                    "1".into(),
1✔
767
                    ComparisonOperator::Equal
1✔
768
                ),
1✔
769
                Function::FilenameVersion(
1✔
770
                    "subdir".into(),
1✔
771
                    regex("Blank\\.esm"),
1✔
772
                    "2".into(),
1✔
773
                    ComparisonOperator::Equal
1✔
774
                )
1✔
775
            );
1✔
776
            assert_ne!(
1✔
777
                Function::FilenameVersion(
1✔
778
                    "subdir".into(),
1✔
779
                    regex("Blank\\.esm"),
1✔
780
                    "1".into(),
1✔
781
                    ComparisonOperator::Equal
1✔
782
                ),
1✔
783
                Function::FilenameVersion(
1✔
784
                    "subdir".into(),
1✔
785
                    regex("Blank\\.esm"),
1✔
786
                    "1".into(),
1✔
787
                    ComparisonOperator::NotEqual
1✔
788
                )
1✔
789
            );
1✔
790
        }
1✔
791

792
        #[test]
793
        fn function_eq_for_filename_version_should_be_case_insensitive_on_pathbuf_and_version() {
1✔
794
            assert_eq!(
1✔
795
                Function::FilenameVersion(
1✔
796
                    "subdir".into(),
1✔
797
                    regex("Blank\\.esm"),
1✔
798
                    "A".into(),
1✔
799
                    ComparisonOperator::Equal
1✔
800
                ),
1✔
801
                Function::FilenameVersion(
1✔
802
                    "Subdir".into(),
1✔
803
                    regex("Blank\\.esm"),
1✔
804
                    "a".into(),
1✔
805
                    ComparisonOperator::Equal
1✔
806
                )
1✔
807
            );
1✔
808
        }
1✔
809

810
        #[test]
811
        fn function_eq_for_description_contains_should_check_pathbuf_and_regex() {
1✔
812
            assert_eq!(
1✔
813
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII)),
1✔
814
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII))
1✔
815
            );
1✔
816

817
            assert_ne!(
1✔
818
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII)),
1✔
819
                Function::DescriptionContains("Blank.esp".into(), regex(".*"))
1✔
820
            );
1✔
821
            assert_ne!(
1✔
822
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII)),
1✔
823
                Function::DescriptionContains("other".into(), regex(LOWERCASE_NON_ASCII))
1✔
824
            );
1✔
825
        }
1✔
826

827
        #[test]
828
        fn function_eq_for_description_contains_should_be_case_insensitive_on_pathbuf_and_regex() {
1✔
829
            assert_eq!(
1✔
830
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII)),
1✔
831
                Function::DescriptionContains("blank.esp".into(), regex(UPPERCASE_NON_ASCII))
1✔
832
            );
1✔
833
        }
1✔
834

835
        #[test]
836
        fn function_eq_description_contains_should_not_be_equal_to_file_regex_with_same_pathbuf_and_regex(
1✔
837
        ) {
1✔
838
            assert_ne!(
1✔
839
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII)),
1✔
840
                Function::FileRegex("Blank.esp".into(), regex(LOWERCASE_NON_ASCII))
1✔
841
            );
1✔
842
        }
1✔
843
    }
844

845
    mod hash {
846
        use super::*;
847

848
        use std::collections::hash_map::DefaultHasher;
849

850
        fn hash(function: &Function) -> u64 {
138✔
851
            let mut hasher = DefaultHasher::new();
138✔
852
            function.hash(&mut hasher);
138✔
853
            hasher.finish()
138✔
854
        }
138✔
855

856
        #[test]
857
        fn function_hash_file_path_should_hash_pathbuf() {
1✔
858
            let function1 = Function::FilePath("Blank.esm".into());
1✔
859
            let function2 = Function::FilePath("Blank.esm".into());
1✔
860

1✔
861
            assert_eq!(hash(&function1), hash(&function2));
1✔
862

863
            let function1 = Function::FilePath("Blank.esm".into());
1✔
864
            let function2 = Function::FilePath("Blank.esp".into());
1✔
865

1✔
866
            assert_ne!(hash(&function1), hash(&function2));
1✔
867
        }
1✔
868

869
        #[test]
870
        fn function_hash_file_path_should_be_case_insensitive() {
1✔
871
            let function1 = Function::FilePath("Blank.esm".into());
1✔
872
            let function2 = Function::FilePath("blank.esm".into());
1✔
873

1✔
874
            assert_eq!(hash(&function1), hash(&function2));
1✔
875
        }
1✔
876

877
        #[test]
878
        fn function_hash_file_regex_should_hash_pathbuf_and_regex() {
1✔
879
            let function1 = Function::FileRegex("subdir".into(), regex(".*"));
1✔
880
            let function2 = Function::FileRegex("subdir".into(), regex(".*"));
1✔
881

1✔
882
            assert_eq!(hash(&function1), hash(&function2));
1✔
883

884
            let function1 = Function::FileRegex("subdir".into(), regex(".*"));
1✔
885
            let function2 = Function::FileRegex("other".into(), regex(".*"));
1✔
886

1✔
887
            assert_ne!(hash(&function1), hash(&function2));
1✔
888

889
            let function1 = Function::FileRegex("subdir".into(), regex(".*"));
1✔
890
            let function2 = Function::FileRegex("subdir".into(), regex("Blank.*"));
1✔
891

1✔
892
            assert_ne!(hash(&function1), hash(&function2));
1✔
893
        }
1✔
894

895
        #[test]
896
        fn function_hash_file_regex_should_be_case_insensitive() {
1✔
897
            let function1 = Function::FileRegex("Subdir".into(), regex("Blank.*"));
1✔
898
            let function2 = Function::FileRegex("subdir".into(), regex("blank.*"));
1✔
899

1✔
900
            assert_eq!(hash(&function1), hash(&function2));
1✔
901
        }
1✔
902

903
        #[test]
904
        fn function_hash_file_size_should_hash_pathbuf_and_size() {
1✔
905
            let function1 = Function::FileSize("subdir".into(), 1);
1✔
906
            let function2 = Function::FileSize("subdir".into(), 1);
1✔
907

1✔
908
            assert_eq!(hash(&function1), hash(&function2));
1✔
909

910
            let function1 = Function::FileSize("subdir".into(), 1);
1✔
911
            let function2 = Function::FileSize("other".into(), 1);
1✔
912

1✔
913
            assert_ne!(hash(&function1), hash(&function2));
1✔
914

915
            let function1 = Function::FileSize("subdir".into(), 1);
1✔
916
            let function2 = Function::FileSize("subdir".into(), 2);
1✔
917

1✔
918
            assert_ne!(hash(&function1), hash(&function2));
1✔
919
        }
1✔
920

921
        #[test]
922
        fn function_hash_file_size_should_be_case_insensitive() {
1✔
923
            let function1 = Function::FileSize("Subdir".into(), 1);
1✔
924
            let function2 = Function::FileSize("subdir".into(), 1);
1✔
925

1✔
926
            assert_eq!(hash(&function1), hash(&function2));
1✔
927
        }
1✔
928

929
        #[test]
930
        fn function_hash_readable_should_hash_pathbuf() {
1✔
931
            let function1 = Function::Readable("Blank.esm".into());
1✔
932
            let function2 = Function::Readable("Blank.esm".into());
1✔
933

1✔
934
            assert_eq!(hash(&function1), hash(&function2));
1✔
935

936
            let function1 = Function::Readable("Blank.esm".into());
1✔
937
            let function2 = Function::Readable("Blank.esp".into());
1✔
938

1✔
939
            assert_ne!(hash(&function1), hash(&function2));
1✔
940
        }
1✔
941

942
        #[test]
943
        fn function_hash_readable_should_be_case_insensitive() {
1✔
944
            let function1 = Function::Readable("Blank.esm".into());
1✔
945
            let function2 = Function::Readable("blank.esm".into());
1✔
946

1✔
947
            assert_eq!(hash(&function1), hash(&function2));
1✔
948
        }
1✔
949

950
        #[test]
951
        fn function_hash_file_path_and_readable_should_not_have_equal_hashes() {
1✔
952
            let function1 = Function::FilePath("Blank.esm".into());
1✔
953
            let function2 = Function::Readable("Blank.esm".into());
1✔
954

1✔
955
            assert_ne!(hash(&function1), hash(&function2));
1✔
956
        }
1✔
957

958
        #[test]
959
        fn function_hash_is_executable_should_hash_pathbuf() {
1✔
960
            let function1 = Function::IsExecutable("Blank.esm".into());
1✔
961
            let function2 = Function::IsExecutable("Blank.esm".into());
1✔
962

1✔
963
            assert_eq!(hash(&function1), hash(&function2));
1✔
964

965
            let function1 = Function::IsExecutable("Blank.esm".into());
1✔
966
            let function2 = Function::IsExecutable("Blank.esp".into());
1✔
967

1✔
968
            assert_ne!(hash(&function1), hash(&function2));
1✔
969
        }
1✔
970

971
        #[test]
972
        fn function_hash_is_executable_should_be_case_insensitive() {
1✔
973
            let function1 = Function::IsExecutable("Blank.esm".into());
1✔
974
            let function2 = Function::IsExecutable("blank.esm".into());
1✔
975

1✔
976
            assert_eq!(hash(&function1), hash(&function2));
1✔
977
        }
1✔
978

979
        #[test]
980
        fn function_hash_file_path_and_readable_and_is_executable_should_not_have_equal_hashes() {
1✔
981
            let function1 = Function::FilePath("Blank.esm".into());
1✔
982
            let function2 = Function::Readable("Blank.esm".into());
1✔
983
            let function3 = Function::IsExecutable("Blank.esm".into());
1✔
984

1✔
985
            assert_ne!(hash(&function1.clone()), hash(&function2.clone()));
1✔
986
            assert_ne!(hash(&function3.clone()), hash(&function1));
1✔
987
            assert_ne!(hash(&function3), hash(&function2));
1✔
988
        }
1✔
989

990
        #[test]
991
        fn function_hash_active_path_should_hash_pathbuf() {
1✔
992
            let function1 = Function::ActivePath("Blank.esm".into());
1✔
993
            let function2 = Function::ActivePath("Blank.esm".into());
1✔
994

1✔
995
            assert_eq!(hash(&function1), hash(&function2));
1✔
996

997
            let function1 = Function::ActivePath("Blank.esm".into());
1✔
998
            let function2 = Function::ActivePath("Blank.esp".into());
1✔
999

1✔
1000
            assert_ne!(hash(&function1), hash(&function2));
1✔
1001
        }
1✔
1002

1003
        #[test]
1004
        fn function_hash_active_path_should_be_case_insensitive() {
1✔
1005
            let function1 = Function::ActivePath("Blank.esm".into());
1✔
1006
            let function2 = Function::ActivePath("blank.esm".into());
1✔
1007

1✔
1008
            assert_eq!(hash(&function1), hash(&function2));
1✔
1009
        }
1✔
1010

1011
        #[test]
1012
        fn function_hash_file_path_and_active_path_should_not_have_equal_hashes() {
1✔
1013
            let function1 = Function::FilePath("Blank.esm".into());
1✔
1014
            let function2 = Function::ActivePath("Blank.esm".into());
1✔
1015

1✔
1016
            assert_ne!(hash(&function1), hash(&function2));
1✔
1017
        }
1✔
1018

1019
        #[test]
1020
        fn function_hash_readable_and_active_path_should_not_have_equal_hashes() {
1✔
1021
            let function1 = Function::Readable("Blank.esm".into());
1✔
1022
            let function2 = Function::ActivePath("Blank.esm".into());
1✔
1023

1✔
1024
            assert_ne!(hash(&function1), hash(&function2));
1✔
1025
        }
1✔
1026

1027
        #[test]
1028
        fn function_hash_active_regex_should_hash_pathbuf_and_regex() {
1✔
1029
            let function1 = Function::ActiveRegex(regex(".*"));
1✔
1030
            let function2 = Function::ActiveRegex(regex(".*"));
1✔
1031

1✔
1032
            assert_eq!(hash(&function1), hash(&function2));
1✔
1033

1034
            let function1 = Function::ActiveRegex(regex(".*"));
1✔
1035
            let function2 = Function::ActiveRegex(regex("Blank.*"));
1✔
1036

1✔
1037
            assert_ne!(hash(&function1), hash(&function2));
1✔
1038
        }
1✔
1039

1040
        #[test]
1041
        fn function_hash_active_regex_should_be_case_insensitive() {
1✔
1042
            let function1 = Function::ActiveRegex(regex("Blank.*"));
1✔
1043
            let function2 = Function::ActiveRegex(regex("blank.*"));
1✔
1044

1✔
1045
            assert_eq!(hash(&function1), hash(&function2));
1✔
1046
        }
1✔
1047

1048
        #[test]
1049
        fn function_hash_is_master_should_hash_pathbuf() {
1✔
1050
            let function1 = Function::IsMaster("Blank.esm".into());
1✔
1051
            let function2 = Function::IsMaster("Blank.esm".into());
1✔
1052

1✔
1053
            assert_eq!(hash(&function1), hash(&function2));
1✔
1054

1055
            let function1 = Function::IsMaster("Blank.esm".into());
1✔
1056
            let function2 = Function::IsMaster("Blank.esp".into());
1✔
1057

1✔
1058
            assert_ne!(hash(&function1), hash(&function2));
1✔
1059
        }
1✔
1060

1061
        #[test]
1062
        fn function_hash_is_master_should_be_case_insensitive() {
1✔
1063
            let function1 = Function::IsMaster("Blank.esm".into());
1✔
1064
            let function2 = Function::IsMaster("blank.esm".into());
1✔
1065

1✔
1066
            assert_eq!(hash(&function1), hash(&function2));
1✔
1067
        }
1✔
1068

1069
        #[test]
1070
        fn function_hash_file_path_and_is_master_should_not_have_equal_hashes() {
1✔
1071
            let function1 = Function::FilePath("Blank.esm".into());
1✔
1072
            let function2 = Function::IsMaster("Blank.esm".into());
1✔
1073

1✔
1074
            assert_ne!(hash(&function1), hash(&function2));
1✔
1075
        }
1✔
1076

1077
        #[test]
1078
        fn function_hash_readable_and_is_master_should_not_have_equal_hashes() {
1✔
1079
            let function1 = Function::Readable("Blank.esm".into());
1✔
1080
            let function2 = Function::IsMaster("Blank.esm".into());
1✔
1081

1✔
1082
            assert_ne!(hash(&function1), hash(&function2));
1✔
1083
        }
1✔
1084

1085
        #[test]
1086
        fn function_hash_active_path_and_is_master_should_not_have_equal_hashes() {
1✔
1087
            let function1 = Function::ActivePath("Blank.esm".into());
1✔
1088
            let function2 = Function::IsMaster("Blank.esm".into());
1✔
1089

1✔
1090
            assert_ne!(hash(&function1), hash(&function2));
1✔
1091
        }
1✔
1092

1093
        #[test]
1094
        fn function_hash_many_should_hash_pathbuf_and_regex() {
1✔
1095
            let function1 = Function::Many("subdir".into(), regex(".*"));
1✔
1096
            let function2 = Function::Many("subdir".into(), regex(".*"));
1✔
1097

1✔
1098
            assert_eq!(hash(&function1), hash(&function2));
1✔
1099

1100
            let function1 = Function::Many("subdir".into(), regex(".*"));
1✔
1101
            let function2 = Function::Many("other".into(), regex(".*"));
1✔
1102

1✔
1103
            assert_ne!(hash(&function1), hash(&function2));
1✔
1104

1105
            let function1 = Function::Many("subdir".into(), regex(".*"));
1✔
1106
            let function2 = Function::Many("subdir".into(), regex("Blank.*"));
1✔
1107

1✔
1108
            assert_ne!(hash(&function1), hash(&function2));
1✔
1109
        }
1✔
1110

1111
        #[test]
1112
        fn function_hash_many_should_be_case_insensitive() {
1✔
1113
            let function1 = Function::Many("Subdir".into(), regex("Blank.*"));
1✔
1114
            let function2 = Function::Many("subdir".into(), regex("blank.*"));
1✔
1115

1✔
1116
            assert_eq!(hash(&function1), hash(&function2));
1✔
1117
        }
1✔
1118

1119
        #[test]
1120
        fn function_hash_file_regex_and_many_should_not_have_equal_hashes() {
1✔
1121
            let function1 = Function::FileRegex("subdir".into(), regex(".*"));
1✔
1122
            let function2 = Function::Many("subdir".into(), regex(".*"));
1✔
1123

1✔
1124
            assert_ne!(hash(&function1), hash(&function2));
1✔
1125
        }
1✔
1126

1127
        #[test]
1128
        fn function_many_active_should_hash_pathbuf_and_regex() {
1✔
1129
            let function1 = Function::ManyActive(regex(".*"));
1✔
1130
            let function2 = Function::ManyActive(regex(".*"));
1✔
1131

1✔
1132
            assert_eq!(hash(&function1), hash(&function2));
1✔
1133

1134
            let function1 = Function::ManyActive(regex(".*"));
1✔
1135
            let function2 = Function::ManyActive(regex("Blank.*"));
1✔
1136

1✔
1137
            assert_ne!(hash(&function1), hash(&function2));
1✔
1138
        }
1✔
1139

1140
        #[test]
1141
        fn function_many_active_should_be_case_insensitive() {
1✔
1142
            let function1 = Function::ManyActive(regex("Blank.*"));
1✔
1143
            let function2 = Function::ManyActive(regex("blank.*"));
1✔
1144

1✔
1145
            assert_eq!(hash(&function1), hash(&function2));
1✔
1146
        }
1✔
1147

1148
        #[test]
1149
        fn function_hash_active_regex_and_many_active_should_not_have_equal_hashes() {
1✔
1150
            let function1 = Function::ActiveRegex(regex(".*"));
1✔
1151
            let function2 = Function::ManyActive(regex(".*"));
1✔
1152

1✔
1153
            assert_ne!(hash(&function1), hash(&function2));
1✔
1154
        }
1✔
1155

1156
        #[test]
1157
        fn function_hash_checksum_should_hash_pathbuf_and_regex() {
1✔
1158
            let function1 = Function::Checksum("subdir".into(), 1);
1✔
1159
            let function2 = Function::Checksum("subdir".into(), 1);
1✔
1160

1✔
1161
            assert_eq!(hash(&function1), hash(&function2));
1✔
1162

1163
            let function1 = Function::Checksum("subdir".into(), 1);
1✔
1164
            let function2 = Function::Checksum("other".into(), 1);
1✔
1165

1✔
1166
            assert_ne!(hash(&function1), hash(&function2));
1✔
1167

1168
            let function1 = Function::Checksum("subdir".into(), 1);
1✔
1169
            let function2 = Function::Checksum("subdir".into(), 2);
1✔
1170

1✔
1171
            assert_ne!(hash(&function1), hash(&function2));
1✔
1172
        }
1✔
1173

1174
        #[test]
1175
        fn function_hash_checksum_should_be_case_insensitive() {
1✔
1176
            let function1 = Function::Checksum("Blank.esm".into(), 1);
1✔
1177
            let function2 = Function::Checksum("Blank.esm".into(), 1);
1✔
1178

1✔
1179
            assert_eq!(hash(&function1), hash(&function2));
1✔
1180
        }
1✔
1181

1182
        #[test]
1183
        fn function_hash_version_should_hash_pathbuf_and_version_and_comparator() {
1✔
1184
            let function1 =
1✔
1185
                Function::Version("Blank.esm".into(), "1.2a".into(), ComparisonOperator::Equal);
1✔
1186
            let function2 =
1✔
1187
                Function::Version("Blank.esm".into(), "1.2a".into(), ComparisonOperator::Equal);
1✔
1188

1✔
1189
            assert_eq!(hash(&function1), hash(&function2));
1✔
1190

1191
            let function1 =
1✔
1192
                Function::Version("Blank.esm".into(), "1".into(), ComparisonOperator::Equal);
1✔
1193
            let function2 =
1✔
1194
                Function::Version("Blank.esp".into(), "1".into(), ComparisonOperator::Equal);
1✔
1195

1✔
1196
            assert_ne!(hash(&function1), hash(&function2));
1✔
1197

1198
            let function1 =
1✔
1199
                Function::Version("Blank.esm".into(), "1".into(), ComparisonOperator::Equal);
1✔
1200
            let function2 =
1✔
1201
                Function::Version("Blank.esm".into(), "2".into(), ComparisonOperator::Equal);
1✔
1202

1✔
1203
            assert_ne!(hash(&function1), hash(&function2));
1✔
1204

1205
            let function1 =
1✔
1206
                Function::Version("Blank.esm".into(), "1".into(), ComparisonOperator::Equal);
1✔
1207
            let function2 =
1✔
1208
                Function::Version("Blank.esm".into(), "1".into(), ComparisonOperator::NotEqual);
1✔
1209

1✔
1210
            assert_ne!(hash(&function1), hash(&function2));
1✔
1211
        }
1✔
1212

1213
        #[test]
1214
        fn function_hash_version_should_be_case_insensitive() {
1✔
1215
            let function1 =
1✔
1216
                Function::Version("Blank.esm".into(), "1.2a".into(), ComparisonOperator::Equal);
1✔
1217
            let function2 =
1✔
1218
                Function::Version("Blank.esm".into(), "1.2A".into(), ComparisonOperator::Equal);
1✔
1219

1✔
1220
            assert_eq!(hash(&function1), hash(&function2));
1✔
1221
        }
1✔
1222

1223
        #[test]
1224
        fn function_hash_product_version_should_hash_pathbuf_and_version_and_comparator() {
1✔
1225
            let function1 = Function::ProductVersion(
1✔
1226
                "Blank.esm".into(),
1✔
1227
                "1.2a".into(),
1✔
1228
                ComparisonOperator::Equal,
1✔
1229
            );
1✔
1230
            let function2 = Function::ProductVersion(
1✔
1231
                "Blank.esm".into(),
1✔
1232
                "1.2a".into(),
1✔
1233
                ComparisonOperator::Equal,
1✔
1234
            );
1✔
1235

1✔
1236
            assert_eq!(hash(&function1), hash(&function2));
1✔
1237

1238
            let function1 =
1✔
1239
                Function::ProductVersion("Blank.esm".into(), "1".into(), ComparisonOperator::Equal);
1✔
1240
            let function2 =
1✔
1241
                Function::ProductVersion("Blank.esp".into(), "1".into(), ComparisonOperator::Equal);
1✔
1242

1✔
1243
            assert_ne!(hash(&function1), hash(&function2));
1✔
1244

1245
            let function1 =
1✔
1246
                Function::ProductVersion("Blank.esm".into(), "1".into(), ComparisonOperator::Equal);
1✔
1247
            let function2 =
1✔
1248
                Function::ProductVersion("Blank.esm".into(), "2".into(), ComparisonOperator::Equal);
1✔
1249

1✔
1250
            assert_ne!(hash(&function1), hash(&function2));
1✔
1251

1252
            let function1 =
1✔
1253
                Function::ProductVersion("Blank.esm".into(), "1".into(), ComparisonOperator::Equal);
1✔
1254
            let function2 = Function::ProductVersion(
1✔
1255
                "Blank.esm".into(),
1✔
1256
                "1".into(),
1✔
1257
                ComparisonOperator::NotEqual,
1✔
1258
            );
1✔
1259

1✔
1260
            assert_ne!(hash(&function1), hash(&function2));
1✔
1261
        }
1✔
1262

1263
        #[test]
1264
        fn function_hash_product_version_should_be_case_insensitive() {
1✔
1265
            let function1 = Function::ProductVersion(
1✔
1266
                "Blank.esm".into(),
1✔
1267
                "1.2a".into(),
1✔
1268
                ComparisonOperator::Equal,
1✔
1269
            );
1✔
1270
            let function2 = Function::ProductVersion(
1✔
1271
                "Blank.esm".into(),
1✔
1272
                "1.2A".into(),
1✔
1273
                ComparisonOperator::Equal,
1✔
1274
            );
1✔
1275

1✔
1276
            assert_eq!(hash(&function1), hash(&function2));
1✔
1277
        }
1✔
1278

1279
        #[test]
1280
        fn function_hash_filename_version_should_hash_pathbuf_regex_and_version_and_comparator() {
1✔
1281
            let function1 = Function::FilenameVersion(
1✔
1282
                "subdir".into(),
1✔
1283
                regex("Blank\\.esm"),
1✔
1284
                "1.2a".into(),
1✔
1285
                ComparisonOperator::Equal,
1✔
1286
            );
1✔
1287
            let function2 = Function::FilenameVersion(
1✔
1288
                "subdir".into(),
1✔
1289
                regex("Blank\\.esm"),
1✔
1290
                "1.2a".into(),
1✔
1291
                ComparisonOperator::Equal,
1✔
1292
            );
1✔
1293

1✔
1294
            assert_eq!(hash(&function1), hash(&function2));
1✔
1295

1296
            let function1 = Function::FilenameVersion(
1✔
1297
                "subdir1".into(),
1✔
1298
                regex("Blank\\.esm"),
1✔
1299
                "1".into(),
1✔
1300
                ComparisonOperator::Equal,
1✔
1301
            );
1✔
1302
            let function2 = Function::FilenameVersion(
1✔
1303
                "subdir2".into(),
1✔
1304
                regex("Blank\\.esp"),
1✔
1305
                "1".into(),
1✔
1306
                ComparisonOperator::Equal,
1✔
1307
            );
1✔
1308

1✔
1309
            assert_ne!(hash(&function1), hash(&function2));
1✔
1310

1311
            let function1 = Function::FilenameVersion(
1✔
1312
                "subdir".into(),
1✔
1313
                regex("Blank\\.esm"),
1✔
1314
                "1".into(),
1✔
1315
                ComparisonOperator::Equal,
1✔
1316
            );
1✔
1317
            let function2 = Function::FilenameVersion(
1✔
1318
                "subdir".into(),
1✔
1319
                regex("Blank\\.esp"),
1✔
1320
                "1".into(),
1✔
1321
                ComparisonOperator::Equal,
1✔
1322
            );
1✔
1323

1✔
1324
            assert_ne!(hash(&function1), hash(&function2));
1✔
1325

1326
            let function1 = Function::FilenameVersion(
1✔
1327
                "subdir".into(),
1✔
1328
                regex("Blank\\.esm"),
1✔
1329
                "1".into(),
1✔
1330
                ComparisonOperator::Equal,
1✔
1331
            );
1✔
1332
            let function2 = Function::FilenameVersion(
1✔
1333
                "subdir".into(),
1✔
1334
                regex("Blank\\.esm"),
1✔
1335
                "2".into(),
1✔
1336
                ComparisonOperator::Equal,
1✔
1337
            );
1✔
1338

1✔
1339
            assert_ne!(hash(&function1), hash(&function2));
1✔
1340

1341
            let function1 = Function::FilenameVersion(
1✔
1342
                "subdir".into(),
1✔
1343
                regex("Blank\\.esm"),
1✔
1344
                "1".into(),
1✔
1345
                ComparisonOperator::Equal,
1✔
1346
            );
1✔
1347
            let function2 = Function::FilenameVersion(
1✔
1348
                "subdir".into(),
1✔
1349
                regex("Blank\\.esm"),
1✔
1350
                "1".into(),
1✔
1351
                ComparisonOperator::NotEqual,
1✔
1352
            );
1✔
1353

1✔
1354
            assert_ne!(hash(&function1), hash(&function2));
1✔
1355
        }
1✔
1356

1357
        #[test]
1358
        fn function_hash_filename_version_should_be_case_insensitive() {
1✔
1359
            let function1 = Function::FilenameVersion(
1✔
1360
                "subdir".into(),
1✔
1361
                regex("Blank\\.esm"),
1✔
1362
                "1.2a".into(),
1✔
1363
                ComparisonOperator::Equal,
1✔
1364
            );
1✔
1365
            let function2 = Function::FilenameVersion(
1✔
1366
                "Subdir".into(),
1✔
1367
                regex("Blank\\.esm"),
1✔
1368
                "1.2A".into(),
1✔
1369
                ComparisonOperator::Equal,
1✔
1370
            );
1✔
1371

1✔
1372
            assert_eq!(hash(&function1), hash(&function2));
1✔
1373
        }
1✔
1374

1375
        #[test]
1376
        fn function_hash_description_contains_should_hash_pathbuf_and_regex() {
1✔
1377
            let function1 =
1✔
1378
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII));
1✔
1379
            let function2 =
1✔
1380
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII));
1✔
1381

1✔
1382
            assert_eq!(hash(&function1), hash(&function2));
1✔
1383

1384
            let function1 =
1✔
1385
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII));
1✔
1386
            let function2 =
1✔
1387
                Function::DescriptionContains("other".into(), regex(LOWERCASE_NON_ASCII));
1✔
1388

1✔
1389
            assert_ne!(hash(&function1), hash(&function2));
1✔
1390

1391
            let function1 =
1✔
1392
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII));
1✔
1393
            let function2 = Function::DescriptionContains("Blank.esp".into(), regex(".*"));
1✔
1394

1✔
1395
            assert_ne!(hash(&function1), hash(&function2));
1✔
1396
        }
1✔
1397

1398
        #[test]
1399
        fn function_hash_description_contains_should_be_case_insensitive() {
1✔
1400
            let function1 =
1✔
1401
                Function::DescriptionContains("blank.esp".into(), regex(UPPERCASE_NON_ASCII));
1✔
1402
            let function2 =
1✔
1403
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII));
1✔
1404

1✔
1405
            assert_eq!(hash(&function1), hash(&function2));
1✔
1406
        }
1✔
1407

1408
        #[test]
1409
        fn function_hash_file_regex_and_description_contains_should_not_have_equal_hashes() {
1✔
1410
            let function1 = Function::FileRegex("Blank.esp".into(), regex(LOWERCASE_NON_ASCII));
1✔
1411
            let function2 =
1✔
1412
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII));
1✔
1413

1✔
1414
            assert_ne!(hash(&function1), hash(&function2));
1✔
1415
        }
1✔
1416
    }
1417
}
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