mirror of
https://github.com/samsonjs/FileOtter.git
synced 2026-03-25 08:25:49 +00:00
159 lines
No EOL
6.7 KiB
Swift
159 lines
No EOL
6.7 KiB
Swift
//
|
|
// FileFnmatchTests.swift
|
|
// FileOtterTests
|
|
//
|
|
// Created by Sami Samhuri on 2025-08-19.
|
|
//
|
|
|
|
@testable import FileOtter
|
|
import XCTest
|
|
|
|
final class FileFnmatchTests: XCTestCase {
|
|
// MARK: - Basic Pattern Tests
|
|
|
|
func testExactMatch() throws {
|
|
XCTAssertTrue(File.fnmatch(pattern: "cat", path: "cat"))
|
|
XCTAssertFalse(File.fnmatch(pattern: "cat", path: "dog"))
|
|
}
|
|
|
|
func testPartialMatch() throws {
|
|
// Must match entire string
|
|
XCTAssertFalse(File.fnmatch(pattern: "cat", path: "category"))
|
|
XCTAssertFalse(File.fnmatch(pattern: "cat", path: "bobcat"))
|
|
}
|
|
|
|
// MARK: - Wildcard Tests
|
|
|
|
func testStarWildcard() throws {
|
|
XCTAssertTrue(File.fnmatch(pattern: "c*", path: "cats"))
|
|
XCTAssertTrue(File.fnmatch(pattern: "c*t", path: "cat"))
|
|
XCTAssertTrue(File.fnmatch(pattern: "c*t", path: "coat"))
|
|
XCTAssertTrue(File.fnmatch(pattern: "*at", path: "cat"))
|
|
XCTAssertTrue(File.fnmatch(pattern: "*at", path: "bat"))
|
|
XCTAssertFalse(File.fnmatch(pattern: "c*t", path: "dog"))
|
|
|
|
// Without pathname flag, * matches /
|
|
XCTAssertTrue(File.fnmatch(pattern: "c*t", path: "c/a/b/t"))
|
|
}
|
|
|
|
func testQuestionMarkWildcard() throws {
|
|
XCTAssertTrue(File.fnmatch(pattern: "c?t", path: "cat"))
|
|
XCTAssertTrue(File.fnmatch(pattern: "c?t", path: "cot"))
|
|
XCTAssertFalse(File.fnmatch(pattern: "c??t", path: "cat"))
|
|
XCTAssertTrue(File.fnmatch(pattern: "c??t", path: "coat"))
|
|
|
|
// ? doesn't match / with pathname flag
|
|
XCTAssertFalse(File.fnmatch(pattern: "c?t", path: "c/t", flags: .pathname))
|
|
}
|
|
|
|
// MARK: - Character Set Tests
|
|
|
|
func testCharacterSet() throws {
|
|
XCTAssertTrue(File.fnmatch(pattern: "ca[a-z]", path: "cat"))
|
|
XCTAssertFalse(File.fnmatch(pattern: "ca[0-9]", path: "cat"))
|
|
XCTAssertTrue(File.fnmatch(pattern: "ca[0-9]", path: "ca5"))
|
|
XCTAssertTrue(File.fnmatch(pattern: "[abc]at", path: "cat"))
|
|
XCTAssertTrue(File.fnmatch(pattern: "[abc]at", path: "bat"))
|
|
XCTAssertFalse(File.fnmatch(pattern: "[abc]at", path: "rat"))
|
|
}
|
|
|
|
func testNegatedCharacterSet() throws {
|
|
XCTAssertFalse(File.fnmatch(pattern: "ca[^t]", path: "cat"))
|
|
XCTAssertTrue(File.fnmatch(pattern: "ca[^t]", path: "cab"))
|
|
XCTAssertTrue(File.fnmatch(pattern: "ca[^t]", path: "can"))
|
|
XCTAssertFalse(File.fnmatch(pattern: "ca[^bcd]", path: "cab"))
|
|
XCTAssertTrue(File.fnmatch(pattern: "ca[^bcd]", path: "cat"))
|
|
}
|
|
|
|
// MARK: - Escape Tests
|
|
|
|
func testEscapedWildcard() throws {
|
|
// With noescape flag, backslash is literal
|
|
XCTAssertTrue(File.fnmatch(pattern: "\\*", path: "\\*", flags: .noescape))
|
|
XCTAssertTrue(File.fnmatch(pattern: "\\?", path: "\\?", flags: .noescape))
|
|
|
|
// Without noescape, backslash escapes the wildcard
|
|
XCTAssertTrue(File.fnmatch(pattern: "\\*", path: "*"))
|
|
XCTAssertTrue(File.fnmatch(pattern: "\\?", path: "?"))
|
|
XCTAssertFalse(File.fnmatch(pattern: "\\*", path: "anything"))
|
|
}
|
|
|
|
func testEscapeInBrackets() throws {
|
|
XCTAssertTrue(File.fnmatch(pattern: "[\\?]", path: "?"))
|
|
XCTAssertTrue(File.fnmatch(pattern: "[\\*]", path: "*"))
|
|
XCTAssertFalse(File.fnmatch(pattern: "[\\?]", path: "a"))
|
|
}
|
|
|
|
// MARK: - Flag Tests
|
|
|
|
func testCaseFoldFlag() throws {
|
|
XCTAssertFalse(File.fnmatch(pattern: "cat", path: "CAT", flags: []))
|
|
XCTAssertTrue(File.fnmatch(pattern: "cat", path: "CAT", flags: .casefold))
|
|
XCTAssertTrue(File.fnmatch(pattern: "CaT", path: "cat", flags: .casefold))
|
|
}
|
|
|
|
func testPathnameFlag() throws {
|
|
// Without pathname flag, * matches /
|
|
XCTAssertTrue(File.fnmatch(pattern: "*", path: "a/b", flags: []))
|
|
|
|
// With pathname flag, * doesn't match /
|
|
XCTAssertFalse(File.fnmatch(pattern: "*", path: "a/b", flags: .pathname))
|
|
XCTAssertTrue(File.fnmatch(pattern: "a/*", path: "a/b", flags: .pathname))
|
|
|
|
// ? also doesn't match / with pathname flag
|
|
XCTAssertFalse(File.fnmatch(pattern: "?", path: "/", flags: .pathname))
|
|
}
|
|
|
|
func testPeriodFlag() throws {
|
|
// By default, * doesn't match leading period (FNM_PERIOD is set)
|
|
XCTAssertFalse(File.fnmatch(pattern: "*", path: ".profile", flags: .period))
|
|
XCTAssertTrue(File.fnmatch(pattern: ".*", path: ".profile", flags: .period))
|
|
|
|
// Without period flag, * can match leading period
|
|
XCTAssertTrue(File.fnmatch(pattern: "*", path: ".profile", flags: []))
|
|
}
|
|
|
|
func testNoescapeFlag() throws {
|
|
// Without noescape, backslash escapes
|
|
XCTAssertTrue(File.fnmatch(pattern: "\\a", path: "a", flags: []))
|
|
XCTAssertFalse(File.fnmatch(pattern: "\\a", path: "\\a", flags: []))
|
|
|
|
// With noescape, backslash is literal
|
|
XCTAssertFalse(File.fnmatch(pattern: "\\a", path: "a", flags: .noescape))
|
|
XCTAssertTrue(File.fnmatch(pattern: "\\a", path: "\\a", flags: .noescape))
|
|
}
|
|
|
|
func testLeadingDirFlag() throws {
|
|
// FNM_LEADING_DIR allows pattern to match a leading portion
|
|
XCTAssertTrue(File.fnmatch(pattern: "*/foo", path: "bar/foo/baz", flags: .leadingDir))
|
|
XCTAssertTrue(File.fnmatch(pattern: "bar/foo", path: "bar/foo/baz", flags: .leadingDir))
|
|
XCTAssertFalse(File.fnmatch(pattern: "bar/foo", path: "bar/foo/baz", flags: []))
|
|
}
|
|
|
|
// MARK: - Complex Pattern Tests
|
|
|
|
func testComplexGlobPatterns() throws {
|
|
// Test various complex patterns
|
|
XCTAssertTrue(File.fnmatch(pattern: "*.txt", path: "file.txt"))
|
|
XCTAssertFalse(File.fnmatch(pattern: "*.txt", path: "file.md"))
|
|
|
|
// Multiple wildcards
|
|
XCTAssertTrue(File.fnmatch(pattern: "*.*", path: "file.txt"))
|
|
XCTAssertTrue(File.fnmatch(pattern: "test_*.rb", path: "test_file.rb"))
|
|
XCTAssertFalse(File.fnmatch(pattern: "test_*.rb", path: "spec_file.rb"))
|
|
}
|
|
|
|
func testHiddenFileMatching() throws {
|
|
// Without special flags, * matches everything including paths with /
|
|
XCTAssertTrue(File.fnmatch(pattern: "*", path: "dave/.profile", flags: []))
|
|
|
|
// With pathname flag, we need to be more specific
|
|
XCTAssertFalse(File.fnmatch(pattern: "*", path: "dave/.profile", flags: .pathname))
|
|
XCTAssertTrue(File.fnmatch(pattern: "dave/*", path: "dave/.profile", flags: .pathname))
|
|
XCTAssertTrue(File.fnmatch(pattern: "dave/.*", path: "dave/.profile", flags: .pathname))
|
|
|
|
// Hidden files in current directory
|
|
XCTAssertFalse(File.fnmatch(pattern: "*", path: ".hidden", flags: .period))
|
|
XCTAssertTrue(File.fnmatch(pattern: ".*", path: ".hidden", flags: .period))
|
|
}
|
|
} |