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

loot / loot-condition-interpreter / 16680825703

01 Aug 2025 05:02PM UTC coverage: 90.615% (-0.9%) from 91.492%
16680825703

push

github

Ortham
Use --workspace instead of deprecated --all

4142 of 4571 relevant lines covered (90.61%)

15.34 hits per line

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

99.46
/src/function/mod.rs
1
#![allow(
2
    clippy::multiple_inherent_impl,
3
    reason = "impl Function is split between parsing and eval"
4
)]
5
use std::fmt;
6
use std::hash::{Hash, Hasher};
7
use std::mem::discriminant;
8
use std::path::PathBuf;
9

10
use regex::Regex;
11
use unicase::eq;
12

13
pub(crate) mod eval;
14
pub(crate) mod parse;
15
mod path;
16
mod version;
17

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

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

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

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

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

133
impl Eq for Function {}
134

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

173
        discriminant(self).hash(state);
258✔
174
    }
258✔
175
}
176

177
#[cfg(test)]
178
mod tests {
179
    use super::*;
180

181
    const LOWERCASE_NON_ASCII: &str = "\u{20ac}\u{192}.";
182
    const UPPERCASE_NON_ASCII: &str = "\u{20ac}\u{191}.";
183

184
    fn regex(string: &str) -> Regex {
114✔
185
        Regex::new(string).unwrap()
114✔
186
    }
114✔
187

188
    mod fmt {
189
        use super::*;
190

191
        #[test]
192
        fn function_fmt_for_file_path_should_format_correctly() {
1✔
193
            let function = Function::FilePath("subdir/Blank.esm".into());
1✔
194

195
            assert_eq!("file(\"subdir/Blank.esm\")", &format!("{function}"));
1✔
196
        }
1✔
197

198
        #[test]
199
        fn function_fmt_for_file_regex_should_format_correctly() {
1✔
200
            let function = Function::FileRegex("subdir".into(), regex("Blank.*"));
1✔
201

202
            assert_eq!("file(\"subdir/Blank.*\")", &format!("{function}"));
1✔
203
        }
1✔
204

205
        #[test]
206
        fn function_fmt_for_file_size_should_format_correctly() {
1✔
207
            let function = Function::FileSize("subdir/Blank.esm".into(), 12_345_678);
1✔
208

209
            assert_eq!(
1✔
210
                "file_size(\"subdir/Blank.esm\", 12345678)",
211
                &format!("{function}")
1✔
212
            );
213
        }
1✔
214

215
        #[test]
216
        fn function_fmt_for_readable_should_format_correctly() {
1✔
217
            let function = Function::Readable("subdir/Blank.esm".into());
1✔
218

219
            assert_eq!("readable(\"subdir/Blank.esm\")", &format!("{function}"));
1✔
220
        }
1✔
221

222
        #[test]
223
        fn function_fmt_for_is_executable_should_format_correctly() {
1✔
224
            let function = Function::IsExecutable("subdir/Blank.esm".into());
1✔
225

226
            assert_eq!(
1✔
227
                "is_executable(\"subdir/Blank.esm\")",
228
                &format!("{function}")
1✔
229
            );
230
        }
1✔
231

232
        #[test]
233
        fn function_fmt_for_active_path_should_format_correctly() {
1✔
234
            let function = Function::ActivePath("Blank.esm".into());
1✔
235

236
            assert_eq!("active(\"Blank.esm\")", &format!("{function}"));
1✔
237
        }
1✔
238

239
        #[test]
240
        fn function_fmt_for_active_regex_should_format_correctly() {
1✔
241
            let function = Function::ActiveRegex(regex("Blank.*"));
1✔
242

243
            assert_eq!("active(\"Blank.*\")", &format!("{function}"));
1✔
244
        }
1✔
245

246
        #[test]
247
        fn function_fmt_for_is_master_should_format_correctly() {
1✔
248
            let function = Function::IsMaster("Blank.esm".into());
1✔
249

250
            assert_eq!("is_master(\"Blank.esm\")", &format!("{function}"));
1✔
251
        }
1✔
252

253
        #[test]
254
        fn function_fmt_for_many_should_format_correctly() {
1✔
255
            let function = Function::Many("subdir".into(), regex("Blank.*"));
1✔
256

257
            assert_eq!("many(\"subdir/Blank.*\")", &format!("{function}"));
1✔
258
        }
1✔
259

260
        #[test]
261
        fn function_fmt_for_many_active_should_format_correctly() {
1✔
262
            let function = Function::ManyActive(regex("Blank.*"));
1✔
263

264
            assert_eq!("many_active(\"Blank.*\")", &format!("{function}"));
1✔
265
        }
1✔
266

267
        #[test]
268
        fn function_fmt_for_checksum_should_format_correctly() {
1✔
269
            let function = Function::Checksum("subdir/Blank.esm".into(), 0xDEAD_BEEF);
1✔
270

271
            assert_eq!(
1✔
272
                "checksum(\"subdir/Blank.esm\", DEADBEEF)",
273
                &format!("{function}")
1✔
274
            );
275
        }
1✔
276

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

285
            assert_eq!(
1✔
286
                "version(\"subdir/Blank.esm\", \"1.2a\", ==)",
287
                &format!("{function}")
1✔
288
            );
289
        }
1✔
290

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

299
            assert_eq!(
1✔
300
                "product_version(\"../TESV.exe\", \"1.2a\", ==)",
301
                &format!("{function}")
1✔
302
            );
303
        }
1✔
304

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

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

320
        #[test]
321
        fn function_fmt_for_description_contains_should_format_correctly() {
1✔
322
            let function =
1✔
323
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII));
1✔
324

325
            assert_eq!(
1✔
326
                &format!("description_contains(\"Blank.esp\", \"{LOWERCASE_NON_ASCII}\")"),
1✔
327
                &format!("{function}")
1✔
328
            );
329
        }
1✔
330
    }
331

332
    mod eq {
333
        use super::*;
334

335
        #[test]
336
        fn function_eq_for_file_path_should_check_pathbuf() {
1✔
337
            assert_eq!(
1✔
338
                Function::FilePath("Blank.esm".into()),
1✔
339
                Function::FilePath("Blank.esm".into())
1✔
340
            );
341

342
            assert_ne!(
1✔
343
                Function::FilePath("Blank.esp".into()),
1✔
344
                Function::FilePath("Blank.esm".into())
1✔
345
            );
346
        }
1✔
347

348
        #[test]
349
        fn function_eq_for_file_path_should_be_case_insensitive_on_pathbuf() {
1✔
350
            assert_eq!(
1✔
351
                Function::FilePath("Blank.esm".into()),
1✔
352
                Function::FilePath("blank.esm".into())
1✔
353
            );
354
        }
1✔
355

356
        #[test]
357
        fn function_eq_for_file_regex_should_check_pathbuf_and_regex() {
1✔
358
            assert_eq!(
1✔
359
                Function::FileRegex("subdir".into(), regex("blank.*")),
1✔
360
                Function::FileRegex("subdir".into(), regex("blank.*"))
1✔
361
            );
362

363
            assert_ne!(
1✔
364
                Function::FileRegex("subdir".into(), regex("blank.*")),
1✔
365
                Function::FileRegex("other".into(), regex("blank.*"))
1✔
366
            );
367
            assert_ne!(
1✔
368
                Function::FileRegex("subdir".into(), regex("blank.*")),
1✔
369
                Function::FileRegex("subdir".into(), regex(".*"))
1✔
370
            );
371
        }
1✔
372

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

381
        #[test]
382
        fn function_eq_for_file_size_should_check_pathbuf_and_size() {
1✔
383
            assert_eq!(
1✔
384
                Function::FileSize("subdir".into(), 1),
1✔
385
                Function::FileSize("subdir".into(), 1)
1✔
386
            );
387

388
            assert_ne!(
1✔
389
                Function::FileSize("subdir".into(), 1),
1✔
390
                Function::FileSize("other".into(), 1)
1✔
391
            );
392
            assert_ne!(
1✔
393
                Function::FileSize("subdir".into(), 1),
1✔
394
                Function::FileSize("subdir".into(), 2)
1✔
395
            );
396
        }
1✔
397

398
        #[test]
399
        fn function_eq_for_file_size_should_be_case_insensitive_on_pathbuf() {
1✔
400
            assert_eq!(
1✔
401
                Function::FileSize("subdir".into(), 1),
1✔
402
                Function::FileSize("Subdir".into(), 1)
1✔
403
            );
404
        }
1✔
405

406
        #[test]
407
        fn function_eq_for_readable_should_check_pathbuf() {
1✔
408
            assert_eq!(
1✔
409
                Function::Readable("Blank.esm".into()),
1✔
410
                Function::Readable("Blank.esm".into())
1✔
411
            );
412

413
            assert_ne!(
1✔
414
                Function::Readable("Blank.esp".into()),
1✔
415
                Function::Readable("Blank.esm".into())
1✔
416
            );
417
        }
1✔
418

419
        #[test]
420
        fn function_eq_for_readable_should_be_case_insensitive_on_pathbuf() {
1✔
421
            assert_eq!(
1✔
422
                Function::Readable("Blank.esm".into()),
1✔
423
                Function::Readable("blank.esm".into())
1✔
424
            );
425
        }
1✔
426

427
        #[test]
428
        fn function_eq_for_readable_should_not_be_equal_to_file_path_with_same_pathbuf() {
1✔
429
            assert_ne!(
1✔
430
                Function::Readable("Blank.esm".into()),
1✔
431
                Function::FilePath("Blank.esm".into())
1✔
432
            );
433
        }
1✔
434

435
        #[test]
436
        fn function_eq_for_is_executable_should_check_pathbuf() {
1✔
437
            assert_eq!(
1✔
438
                Function::IsExecutable("Blank.esm".into()),
1✔
439
                Function::IsExecutable("Blank.esm".into())
1✔
440
            );
441

442
            assert_ne!(
1✔
443
                Function::IsExecutable("Blank.esp".into()),
1✔
444
                Function::IsExecutable("Blank.esm".into())
1✔
445
            );
446
        }
1✔
447

448
        #[test]
449
        fn function_eq_for_is_executable_should_be_case_insensitive_on_pathbuf() {
1✔
450
            assert_eq!(
1✔
451
                Function::IsExecutable("Blank.esm".into()),
1✔
452
                Function::IsExecutable("blank.esm".into())
1✔
453
            );
454
        }
1✔
455

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

469
        #[test]
470
        fn function_eq_for_active_path_should_check_pathbuf() {
1✔
471
            assert_eq!(
1✔
472
                Function::ActivePath("Blank.esm".into()),
1✔
473
                Function::ActivePath("Blank.esm".into())
1✔
474
            );
475

476
            assert_ne!(
1✔
477
                Function::ActivePath("Blank.esp".into()),
1✔
478
                Function::ActivePath("Blank.esm".into())
1✔
479
            );
480
        }
1✔
481

482
        #[test]
483
        fn function_eq_for_active_path_should_be_case_insensitive_on_pathbuf() {
1✔
484
            assert_eq!(
1✔
485
                Function::ActivePath("Blank.esm".into()),
1✔
486
                Function::ActivePath("blank.esm".into())
1✔
487
            );
488
        }
1✔
489

490
        #[test]
491
        fn function_eq_for_active_path_should_not_be_equal_to_file_path_with_same_pathbuf() {
1✔
492
            assert_ne!(
1✔
493
                Function::ActivePath("Blank.esm".into()),
1✔
494
                Function::FilePath("Blank.esm".into())
1✔
495
            );
496
        }
1✔
497

498
        #[test]
499
        fn function_eq_for_active_path_should_not_be_equal_to_readable_with_same_pathbuf() {
1✔
500
            assert_ne!(
1✔
501
                Function::ActivePath("Blank.esm".into()),
1✔
502
                Function::Readable("Blank.esm".into())
1✔
503
            );
504
        }
1✔
505

506
        #[test]
507
        fn function_eq_for_active_regex_should_check_regex() {
1✔
508
            assert_eq!(
1✔
509
                Function::ActiveRegex(regex("blank.*")),
1✔
510
                Function::ActiveRegex(regex("blank.*"))
1✔
511
            );
512

513
            assert_ne!(
1✔
514
                Function::ActiveRegex(regex("blank.*")),
1✔
515
                Function::ActiveRegex(regex(".*"))
1✔
516
            );
517
        }
1✔
518

519
        #[test]
520
        fn function_eq_for_active_regex_should_be_case_insensitive_on_regex() {
1✔
521
            assert_eq!(
1✔
522
                Function::ActiveRegex(regex("blank.*")),
1✔
523
                Function::ActiveRegex(regex("Blank.*"))
1✔
524
            );
525
        }
1✔
526

527
        #[test]
528
        fn function_eq_for_is_master_should_check_pathbuf() {
1✔
529
            assert_eq!(
1✔
530
                Function::IsMaster("Blank.esm".into()),
1✔
531
                Function::IsMaster("Blank.esm".into())
1✔
532
            );
533

534
            assert_ne!(
1✔
535
                Function::IsMaster("Blank.esp".into()),
1✔
536
                Function::IsMaster("Blank.esm".into())
1✔
537
            );
538
        }
1✔
539

540
        #[test]
541
        fn function_eq_for_is_master_should_be_case_insensitive_on_pathbuf() {
1✔
542
            assert_eq!(
1✔
543
                Function::IsMaster("Blank.esm".into()),
1✔
544
                Function::IsMaster("blank.esm".into())
1✔
545
            );
546
        }
1✔
547

548
        #[test]
549
        fn function_eq_for_is_master_should_not_be_equal_to_file_path_with_same_pathbuf() {
1✔
550
            assert_ne!(
1✔
551
                Function::IsMaster("Blank.esm".into()),
1✔
552
                Function::FilePath("Blank.esm".into())
1✔
553
            );
554
        }
1✔
555

556
        #[test]
557
        fn function_eq_for_is_master_should_not_be_equal_to_readable_with_same_pathbuf() {
1✔
558
            assert_ne!(
1✔
559
                Function::IsMaster("Blank.esm".into()),
1✔
560
                Function::Readable("Blank.esm".into())
1✔
561
            );
562
        }
1✔
563

564
        #[test]
565
        fn function_eq_for_is_master_should_not_be_equal_to_active_path_with_same_pathbuf() {
1✔
566
            assert_ne!(
1✔
567
                Function::IsMaster("Blank.esm".into()),
1✔
568
                Function::ActivePath("Blank.esm".into())
1✔
569
            );
570
        }
1✔
571

572
        #[test]
573
        fn function_eq_for_many_should_check_pathbuf_and_regex() {
1✔
574
            assert_eq!(
1✔
575
                Function::Many("subdir".into(), regex("blank.*")),
1✔
576
                Function::Many("subdir".into(), regex("blank.*"))
1✔
577
            );
578

579
            assert_ne!(
1✔
580
                Function::Many("subdir".into(), regex("blank.*")),
1✔
581
                Function::Many("subdir".into(), regex(".*"))
1✔
582
            );
583
            assert_ne!(
1✔
584
                Function::Many("subdir".into(), regex("blank.*")),
1✔
585
                Function::Many("other".into(), regex("blank.*"))
1✔
586
            );
587
        }
1✔
588

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

597
        #[test]
598
        fn function_eq_many_should_not_be_equal_to_file_regex_with_same_pathbuf_and_regex() {
1✔
599
            assert_ne!(
1✔
600
                Function::Many("subdir".into(), regex("blank.*")),
1✔
601
                Function::FileRegex("subdir".into(), regex("blank.*"))
1✔
602
            );
603
        }
1✔
604

605
        #[test]
606
        fn function_eq_for_many_active_should_check_regex() {
1✔
607
            assert_eq!(
1✔
608
                Function::ManyActive(regex("blank.*")),
1✔
609
                Function::ManyActive(regex("blank.*"))
1✔
610
            );
611

612
            assert_ne!(
1✔
613
                Function::ManyActive(regex("blank.*")),
1✔
614
                Function::ManyActive(regex(".*"))
1✔
615
            );
616
        }
1✔
617

618
        #[test]
619
        fn function_eq_for_many_active_should_be_case_insensitive_on_regex() {
1✔
620
            assert_eq!(
1✔
621
                Function::ManyActive(regex("blank.*")),
1✔
622
                Function::ManyActive(regex("Blank.*"))
1✔
623
            );
624
        }
1✔
625

626
        #[test]
627
        fn function_eq_many_active_should_not_be_equal_to_active_regex_with_same_regex() {
1✔
628
            assert_ne!(
1✔
629
                Function::ManyActive(regex("blank.*")),
1✔
630
                Function::ActiveRegex(regex("blank.*"))
1✔
631
            );
632
        }
1✔
633

634
        #[test]
635
        fn function_eq_for_checksum_should_check_pathbuf_and_crc() {
1✔
636
            assert_eq!(
1✔
637
                Function::Checksum("Blank.esm".into(), 1),
1✔
638
                Function::Checksum("Blank.esm".into(), 1)
1✔
639
            );
640

641
            assert_ne!(
1✔
642
                Function::Checksum("Blank.esm".into(), 1),
1✔
643
                Function::Checksum("Blank.esm".into(), 2)
1✔
644
            );
645
            assert_ne!(
1✔
646
                Function::Checksum("Blank.esm".into(), 1),
1✔
647
                Function::Checksum("Blank.esp".into(), 1)
1✔
648
            );
649
        }
1✔
650

651
        #[test]
652
        fn function_eq_for_checksum_should_be_case_insensitive_on_pathbuf() {
1✔
653
            assert_eq!(
1✔
654
                Function::Checksum("Blank.esm".into(), 1),
1✔
655
                Function::Checksum("blank.esm".into(), 1)
1✔
656
            );
657
        }
1✔
658

659
        #[test]
660
        fn function_eq_for_version_should_check_pathbuf_version_and_comparator() {
1✔
661
            assert_eq!(
1✔
662
                Function::Version("Blank.esm".into(), "1".into(), ComparisonOperator::Equal),
1✔
663
                Function::Version("Blank.esm".into(), "1".into(), ComparisonOperator::Equal)
1✔
664
            );
665

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

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

688
        #[test]
689
        fn function_eq_for_product_version_should_check_pathbuf_version_and_comparator() {
1✔
690
            assert_eq!(
1✔
691
                Function::ProductVersion("Blank.esm".into(), "1".into(), ComparisonOperator::Equal),
1✔
692
                Function::ProductVersion("Blank.esm".into(), "1".into(), ComparisonOperator::Equal)
1✔
693
            );
694

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

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

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

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

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

814
        #[test]
815
        fn function_eq_for_description_contains_should_check_pathbuf_and_regex() {
1✔
816
            assert_eq!(
1✔
817
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII)),
1✔
818
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII))
1✔
819
            );
820

821
            assert_ne!(
1✔
822
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII)),
1✔
823
                Function::DescriptionContains("Blank.esp".into(), regex(".*"))
1✔
824
            );
825
            assert_ne!(
1✔
826
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII)),
1✔
827
                Function::DescriptionContains("other".into(), regex(LOWERCASE_NON_ASCII))
1✔
828
            );
829
        }
1✔
830

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

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

849
    mod hash {
850
        use super::*;
851

852
        use std::collections::hash_map::DefaultHasher;
853

854
        fn hash(function: &Function) -> u64 {
138✔
855
            let mut hasher = DefaultHasher::new();
138✔
856
            function.hash(&mut hasher);
138✔
857
            hasher.finish()
138✔
858
        }
138✔
859

860
        #[test]
861
        fn function_hash_file_path_should_hash_pathbuf() {
1✔
862
            let function1 = Function::FilePath("Blank.esm".into());
1✔
863
            let function2 = Function::FilePath("Blank.esm".into());
1✔
864

865
            assert_eq!(hash(&function1), hash(&function2));
1✔
866

867
            let function1 = Function::FilePath("Blank.esm".into());
1✔
868
            let function2 = Function::FilePath("Blank.esp".into());
1✔
869

870
            assert_ne!(hash(&function1), hash(&function2));
1✔
871
        }
1✔
872

873
        #[test]
874
        fn function_hash_file_path_should_be_case_insensitive() {
1✔
875
            let function1 = Function::FilePath("Blank.esm".into());
1✔
876
            let function2 = Function::FilePath("blank.esm".into());
1✔
877

878
            assert_eq!(hash(&function1), hash(&function2));
1✔
879
        }
1✔
880

881
        #[test]
882
        fn function_hash_file_regex_should_hash_pathbuf_and_regex() {
1✔
883
            let function1 = Function::FileRegex("subdir".into(), regex(".*"));
1✔
884
            let function2 = Function::FileRegex("subdir".into(), regex(".*"));
1✔
885

886
            assert_eq!(hash(&function1), hash(&function2));
1✔
887

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

891
            assert_ne!(hash(&function1), hash(&function2));
1✔
892

893
            let function1 = Function::FileRegex("subdir".into(), regex(".*"));
1✔
894
            let function2 = Function::FileRegex("subdir".into(), regex("Blank.*"));
1✔
895

896
            assert_ne!(hash(&function1), hash(&function2));
1✔
897
        }
1✔
898

899
        #[test]
900
        fn function_hash_file_regex_should_be_case_insensitive() {
1✔
901
            let function1 = Function::FileRegex("Subdir".into(), regex("Blank.*"));
1✔
902
            let function2 = Function::FileRegex("subdir".into(), regex("blank.*"));
1✔
903

904
            assert_eq!(hash(&function1), hash(&function2));
1✔
905
        }
1✔
906

907
        #[test]
908
        fn function_hash_file_size_should_hash_pathbuf_and_size() {
1✔
909
            let function1 = Function::FileSize("subdir".into(), 1);
1✔
910
            let function2 = Function::FileSize("subdir".into(), 1);
1✔
911

912
            assert_eq!(hash(&function1), hash(&function2));
1✔
913

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

917
            assert_ne!(hash(&function1), hash(&function2));
1✔
918

919
            let function1 = Function::FileSize("subdir".into(), 1);
1✔
920
            let function2 = Function::FileSize("subdir".into(), 2);
1✔
921

922
            assert_ne!(hash(&function1), hash(&function2));
1✔
923
        }
1✔
924

925
        #[test]
926
        fn function_hash_file_size_should_be_case_insensitive() {
1✔
927
            let function1 = Function::FileSize("Subdir".into(), 1);
1✔
928
            let function2 = Function::FileSize("subdir".into(), 1);
1✔
929

930
            assert_eq!(hash(&function1), hash(&function2));
1✔
931
        }
1✔
932

933
        #[test]
934
        fn function_hash_readable_should_hash_pathbuf() {
1✔
935
            let function1 = Function::Readable("Blank.esm".into());
1✔
936
            let function2 = Function::Readable("Blank.esm".into());
1✔
937

938
            assert_eq!(hash(&function1), hash(&function2));
1✔
939

940
            let function1 = Function::Readable("Blank.esm".into());
1✔
941
            let function2 = Function::Readable("Blank.esp".into());
1✔
942

943
            assert_ne!(hash(&function1), hash(&function2));
1✔
944
        }
1✔
945

946
        #[test]
947
        fn function_hash_readable_should_be_case_insensitive() {
1✔
948
            let function1 = Function::Readable("Blank.esm".into());
1✔
949
            let function2 = Function::Readable("blank.esm".into());
1✔
950

951
            assert_eq!(hash(&function1), hash(&function2));
1✔
952
        }
1✔
953

954
        #[test]
955
        fn function_hash_file_path_and_readable_should_not_have_equal_hashes() {
1✔
956
            let function1 = Function::FilePath("Blank.esm".into());
1✔
957
            let function2 = Function::Readable("Blank.esm".into());
1✔
958

959
            assert_ne!(hash(&function1), hash(&function2));
1✔
960
        }
1✔
961

962
        #[test]
963
        fn function_hash_is_executable_should_hash_pathbuf() {
1✔
964
            let function1 = Function::IsExecutable("Blank.esm".into());
1✔
965
            let function2 = Function::IsExecutable("Blank.esm".into());
1✔
966

967
            assert_eq!(hash(&function1), hash(&function2));
1✔
968

969
            let function1 = Function::IsExecutable("Blank.esm".into());
1✔
970
            let function2 = Function::IsExecutable("Blank.esp".into());
1✔
971

972
            assert_ne!(hash(&function1), hash(&function2));
1✔
973
        }
1✔
974

975
        #[test]
976
        fn function_hash_is_executable_should_be_case_insensitive() {
1✔
977
            let function1 = Function::IsExecutable("Blank.esm".into());
1✔
978
            let function2 = Function::IsExecutable("blank.esm".into());
1✔
979

980
            assert_eq!(hash(&function1), hash(&function2));
1✔
981
        }
1✔
982

983
        #[test]
984
        fn function_hash_file_path_and_readable_and_is_executable_should_not_have_equal_hashes() {
1✔
985
            let function1 = Function::FilePath("Blank.esm".into());
1✔
986
            let function2 = Function::Readable("Blank.esm".into());
1✔
987
            let function3 = Function::IsExecutable("Blank.esm".into());
1✔
988

989
            assert_ne!(hash(&function1.clone()), hash(&function2.clone()));
1✔
990
            assert_ne!(hash(&function3.clone()), hash(&function1));
1✔
991
            assert_ne!(hash(&function3), hash(&function2));
1✔
992
        }
1✔
993

994
        #[test]
995
        fn function_hash_active_path_should_hash_pathbuf() {
1✔
996
            let function1 = Function::ActivePath("Blank.esm".into());
1✔
997
            let function2 = Function::ActivePath("Blank.esm".into());
1✔
998

999
            assert_eq!(hash(&function1), hash(&function2));
1✔
1000

1001
            let function1 = Function::ActivePath("Blank.esm".into());
1✔
1002
            let function2 = Function::ActivePath("Blank.esp".into());
1✔
1003

1004
            assert_ne!(hash(&function1), hash(&function2));
1✔
1005
        }
1✔
1006

1007
        #[test]
1008
        fn function_hash_active_path_should_be_case_insensitive() {
1✔
1009
            let function1 = Function::ActivePath("Blank.esm".into());
1✔
1010
            let function2 = Function::ActivePath("blank.esm".into());
1✔
1011

1012
            assert_eq!(hash(&function1), hash(&function2));
1✔
1013
        }
1✔
1014

1015
        #[test]
1016
        fn function_hash_file_path_and_active_path_should_not_have_equal_hashes() {
1✔
1017
            let function1 = Function::FilePath("Blank.esm".into());
1✔
1018
            let function2 = Function::ActivePath("Blank.esm".into());
1✔
1019

1020
            assert_ne!(hash(&function1), hash(&function2));
1✔
1021
        }
1✔
1022

1023
        #[test]
1024
        fn function_hash_readable_and_active_path_should_not_have_equal_hashes() {
1✔
1025
            let function1 = Function::Readable("Blank.esm".into());
1✔
1026
            let function2 = Function::ActivePath("Blank.esm".into());
1✔
1027

1028
            assert_ne!(hash(&function1), hash(&function2));
1✔
1029
        }
1✔
1030

1031
        #[test]
1032
        fn function_hash_active_regex_should_hash_pathbuf_and_regex() {
1✔
1033
            let function1 = Function::ActiveRegex(regex(".*"));
1✔
1034
            let function2 = Function::ActiveRegex(regex(".*"));
1✔
1035

1036
            assert_eq!(hash(&function1), hash(&function2));
1✔
1037

1038
            let function1 = Function::ActiveRegex(regex(".*"));
1✔
1039
            let function2 = Function::ActiveRegex(regex("Blank.*"));
1✔
1040

1041
            assert_ne!(hash(&function1), hash(&function2));
1✔
1042
        }
1✔
1043

1044
        #[test]
1045
        fn function_hash_active_regex_should_be_case_insensitive() {
1✔
1046
            let function1 = Function::ActiveRegex(regex("Blank.*"));
1✔
1047
            let function2 = Function::ActiveRegex(regex("blank.*"));
1✔
1048

1049
            assert_eq!(hash(&function1), hash(&function2));
1✔
1050
        }
1✔
1051

1052
        #[test]
1053
        fn function_hash_is_master_should_hash_pathbuf() {
1✔
1054
            let function1 = Function::IsMaster("Blank.esm".into());
1✔
1055
            let function2 = Function::IsMaster("Blank.esm".into());
1✔
1056

1057
            assert_eq!(hash(&function1), hash(&function2));
1✔
1058

1059
            let function1 = Function::IsMaster("Blank.esm".into());
1✔
1060
            let function2 = Function::IsMaster("Blank.esp".into());
1✔
1061

1062
            assert_ne!(hash(&function1), hash(&function2));
1✔
1063
        }
1✔
1064

1065
        #[test]
1066
        fn function_hash_is_master_should_be_case_insensitive() {
1✔
1067
            let function1 = Function::IsMaster("Blank.esm".into());
1✔
1068
            let function2 = Function::IsMaster("blank.esm".into());
1✔
1069

1070
            assert_eq!(hash(&function1), hash(&function2));
1✔
1071
        }
1✔
1072

1073
        #[test]
1074
        fn function_hash_file_path_and_is_master_should_not_have_equal_hashes() {
1✔
1075
            let function1 = Function::FilePath("Blank.esm".into());
1✔
1076
            let function2 = Function::IsMaster("Blank.esm".into());
1✔
1077

1078
            assert_ne!(hash(&function1), hash(&function2));
1✔
1079
        }
1✔
1080

1081
        #[test]
1082
        fn function_hash_readable_and_is_master_should_not_have_equal_hashes() {
1✔
1083
            let function1 = Function::Readable("Blank.esm".into());
1✔
1084
            let function2 = Function::IsMaster("Blank.esm".into());
1✔
1085

1086
            assert_ne!(hash(&function1), hash(&function2));
1✔
1087
        }
1✔
1088

1089
        #[test]
1090
        fn function_hash_active_path_and_is_master_should_not_have_equal_hashes() {
1✔
1091
            let function1 = Function::ActivePath("Blank.esm".into());
1✔
1092
            let function2 = Function::IsMaster("Blank.esm".into());
1✔
1093

1094
            assert_ne!(hash(&function1), hash(&function2));
1✔
1095
        }
1✔
1096

1097
        #[test]
1098
        fn function_hash_many_should_hash_pathbuf_and_regex() {
1✔
1099
            let function1 = Function::Many("subdir".into(), regex(".*"));
1✔
1100
            let function2 = Function::Many("subdir".into(), regex(".*"));
1✔
1101

1102
            assert_eq!(hash(&function1), hash(&function2));
1✔
1103

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

1107
            assert_ne!(hash(&function1), hash(&function2));
1✔
1108

1109
            let function1 = Function::Many("subdir".into(), regex(".*"));
1✔
1110
            let function2 = Function::Many("subdir".into(), regex("Blank.*"));
1✔
1111

1112
            assert_ne!(hash(&function1), hash(&function2));
1✔
1113
        }
1✔
1114

1115
        #[test]
1116
        fn function_hash_many_should_be_case_insensitive() {
1✔
1117
            let function1 = Function::Many("Subdir".into(), regex("Blank.*"));
1✔
1118
            let function2 = Function::Many("subdir".into(), regex("blank.*"));
1✔
1119

1120
            assert_eq!(hash(&function1), hash(&function2));
1✔
1121
        }
1✔
1122

1123
        #[test]
1124
        fn function_hash_file_regex_and_many_should_not_have_equal_hashes() {
1✔
1125
            let function1 = Function::FileRegex("subdir".into(), regex(".*"));
1✔
1126
            let function2 = Function::Many("subdir".into(), regex(".*"));
1✔
1127

1128
            assert_ne!(hash(&function1), hash(&function2));
1✔
1129
        }
1✔
1130

1131
        #[test]
1132
        fn function_many_active_should_hash_pathbuf_and_regex() {
1✔
1133
            let function1 = Function::ManyActive(regex(".*"));
1✔
1134
            let function2 = Function::ManyActive(regex(".*"));
1✔
1135

1136
            assert_eq!(hash(&function1), hash(&function2));
1✔
1137

1138
            let function1 = Function::ManyActive(regex(".*"));
1✔
1139
            let function2 = Function::ManyActive(regex("Blank.*"));
1✔
1140

1141
            assert_ne!(hash(&function1), hash(&function2));
1✔
1142
        }
1✔
1143

1144
        #[test]
1145
        fn function_many_active_should_be_case_insensitive() {
1✔
1146
            let function1 = Function::ManyActive(regex("Blank.*"));
1✔
1147
            let function2 = Function::ManyActive(regex("blank.*"));
1✔
1148

1149
            assert_eq!(hash(&function1), hash(&function2));
1✔
1150
        }
1✔
1151

1152
        #[test]
1153
        fn function_hash_active_regex_and_many_active_should_not_have_equal_hashes() {
1✔
1154
            let function1 = Function::ActiveRegex(regex(".*"));
1✔
1155
            let function2 = Function::ManyActive(regex(".*"));
1✔
1156

1157
            assert_ne!(hash(&function1), hash(&function2));
1✔
1158
        }
1✔
1159

1160
        #[test]
1161
        fn function_hash_checksum_should_hash_pathbuf_and_regex() {
1✔
1162
            let function1 = Function::Checksum("subdir".into(), 1);
1✔
1163
            let function2 = Function::Checksum("subdir".into(), 1);
1✔
1164

1165
            assert_eq!(hash(&function1), hash(&function2));
1✔
1166

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

1170
            assert_ne!(hash(&function1), hash(&function2));
1✔
1171

1172
            let function1 = Function::Checksum("subdir".into(), 1);
1✔
1173
            let function2 = Function::Checksum("subdir".into(), 2);
1✔
1174

1175
            assert_ne!(hash(&function1), hash(&function2));
1✔
1176
        }
1✔
1177

1178
        #[test]
1179
        fn function_hash_checksum_should_be_case_insensitive() {
1✔
1180
            let function1 = Function::Checksum("Blank.esm".into(), 1);
1✔
1181
            let function2 = Function::Checksum("Blank.esm".into(), 1);
1✔
1182

1183
            assert_eq!(hash(&function1), hash(&function2));
1✔
1184
        }
1✔
1185

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

1193
            assert_eq!(hash(&function1), hash(&function2));
1✔
1194

1195
            let function1 =
1✔
1196
                Function::Version("Blank.esm".into(), "1".into(), ComparisonOperator::Equal);
1✔
1197
            let function2 =
1✔
1198
                Function::Version("Blank.esp".into(), "1".into(), ComparisonOperator::Equal);
1✔
1199

1200
            assert_ne!(hash(&function1), hash(&function2));
1✔
1201

1202
            let function1 =
1✔
1203
                Function::Version("Blank.esm".into(), "1".into(), ComparisonOperator::Equal);
1✔
1204
            let function2 =
1✔
1205
                Function::Version("Blank.esm".into(), "2".into(), ComparisonOperator::Equal);
1✔
1206

1207
            assert_ne!(hash(&function1), hash(&function2));
1✔
1208

1209
            let function1 =
1✔
1210
                Function::Version("Blank.esm".into(), "1".into(), ComparisonOperator::Equal);
1✔
1211
            let function2 =
1✔
1212
                Function::Version("Blank.esm".into(), "1".into(), ComparisonOperator::NotEqual);
1✔
1213

1214
            assert_ne!(hash(&function1), hash(&function2));
1✔
1215
        }
1✔
1216

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

1224
            assert_eq!(hash(&function1), hash(&function2));
1✔
1225
        }
1✔
1226

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

1240
            assert_eq!(hash(&function1), hash(&function2));
1✔
1241

1242
            let function1 =
1✔
1243
                Function::ProductVersion("Blank.esm".into(), "1".into(), ComparisonOperator::Equal);
1✔
1244
            let function2 =
1✔
1245
                Function::ProductVersion("Blank.esp".into(), "1".into(), ComparisonOperator::Equal);
1✔
1246

1247
            assert_ne!(hash(&function1), hash(&function2));
1✔
1248

1249
            let function1 =
1✔
1250
                Function::ProductVersion("Blank.esm".into(), "1".into(), ComparisonOperator::Equal);
1✔
1251
            let function2 =
1✔
1252
                Function::ProductVersion("Blank.esm".into(), "2".into(), ComparisonOperator::Equal);
1✔
1253

1254
            assert_ne!(hash(&function1), hash(&function2));
1✔
1255

1256
            let function1 =
1✔
1257
                Function::ProductVersion("Blank.esm".into(), "1".into(), ComparisonOperator::Equal);
1✔
1258
            let function2 = Function::ProductVersion(
1✔
1259
                "Blank.esm".into(),
1✔
1260
                "1".into(),
1✔
1261
                ComparisonOperator::NotEqual,
1✔
1262
            );
1✔
1263

1264
            assert_ne!(hash(&function1), hash(&function2));
1✔
1265
        }
1✔
1266

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

1280
            assert_eq!(hash(&function1), hash(&function2));
1✔
1281
        }
1✔
1282

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

1298
            assert_eq!(hash(&function1), hash(&function2));
1✔
1299

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

1313
            assert_ne!(hash(&function1), hash(&function2));
1✔
1314

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

1328
            assert_ne!(hash(&function1), hash(&function2));
1✔
1329

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

1343
            assert_ne!(hash(&function1), hash(&function2));
1✔
1344

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

1358
            assert_ne!(hash(&function1), hash(&function2));
1✔
1359
        }
1✔
1360

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

1376
            assert_eq!(hash(&function1), hash(&function2));
1✔
1377
        }
1✔
1378

1379
        #[test]
1380
        fn function_hash_description_contains_should_hash_pathbuf_and_regex() {
1✔
1381
            let function1 =
1✔
1382
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII));
1✔
1383
            let function2 =
1✔
1384
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII));
1✔
1385

1386
            assert_eq!(hash(&function1), hash(&function2));
1✔
1387

1388
            let function1 =
1✔
1389
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII));
1✔
1390
            let function2 =
1✔
1391
                Function::DescriptionContains("other".into(), regex(LOWERCASE_NON_ASCII));
1✔
1392

1393
            assert_ne!(hash(&function1), hash(&function2));
1✔
1394

1395
            let function1 =
1✔
1396
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII));
1✔
1397
            let function2 = Function::DescriptionContains("Blank.esp".into(), regex(".*"));
1✔
1398

1399
            assert_ne!(hash(&function1), hash(&function2));
1✔
1400
        }
1✔
1401

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

1409
            assert_eq!(hash(&function1), hash(&function2));
1✔
1410
        }
1✔
1411

1412
        #[test]
1413
        fn function_hash_file_regex_and_description_contains_should_not_have_equal_hashes() {
1✔
1414
            let function1 = Function::FileRegex("Blank.esp".into(), regex(LOWERCASE_NON_ASCII));
1✔
1415
            let function2 =
1✔
1416
                Function::DescriptionContains("Blank.esp".into(), regex(LOWERCASE_NON_ASCII));
1✔
1417

1418
            assert_ne!(hash(&function1), hash(&function2));
1✔
1419
        }
1✔
1420
    }
1421
}
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