mirror of
https://github.com/coteditor/CotEditor.git
synced 2024-08-16 14:50:30 +03:00
Migrate unit tests to Swift Testing
This commit is contained in:
parent
d7ec330ed4
commit
dffbcfecf0
@ -27,6 +27,7 @@
|
||||
- [trivial] Suppress display of the “Extracting” message on the navigation bar in instantaneous parsing.
|
||||
- [trivial] Make names of code contributors in the About window selectable.
|
||||
- [dev] Update the build environment to Xcode 16.
|
||||
- [dev] Migrate all unit tests to Swift Testing.
|
||||
- [dev] Migrate the navigation bar and the Snippets settings view to SwiftUI.
|
||||
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2022 1024jp
|
||||
// © 2022-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -23,14 +23,14 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class ArithmeticsTests: XCTestCase {
|
||||
struct ArithmeticsTests {
|
||||
|
||||
func testDigits() {
|
||||
@Test func digits() {
|
||||
|
||||
XCTAssertEqual(0.digits, [0])
|
||||
XCTAssertEqual(1024.digits, [4, 2, 0, 1])
|
||||
#expect(0.digits == [0])
|
||||
#expect(1024.digits == [4, 2, 0, 1])
|
||||
}
|
||||
}
|
||||
|
@ -24,69 +24,64 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class BracePairTests: XCTestCase {
|
||||
struct BracePairTests {
|
||||
|
||||
func testIndexFind() {
|
||||
@Test func findIndex() {
|
||||
|
||||
let string = "if < foo < 🐕 > > else < >"
|
||||
let pair = BracePair("<", ">")
|
||||
|
||||
XCTAssertEqual(string.indexOfBracePair(endIndex: string.index(14), pair: pair), string.index(3))
|
||||
XCTAssertEqual(string.indexOfBracePair(beginIndex: string.index(4), pair: pair), string.index(15))
|
||||
XCTAssertNil(string.indexOfBracePair(endIndex: string.index(2), pair: pair))
|
||||
XCTAssertNil(string.indexOfBracePair(beginIndex: string.index(2), pair: .ltgt))
|
||||
#expect(string.indexOfBracePair(endIndex: string.index(14), pair: pair) == string.index(3))
|
||||
#expect(string.indexOfBracePair(beginIndex: string.index(4), pair: pair) == string.index(15))
|
||||
#expect(string.indexOfBracePair(endIndex: string.index(2), pair: pair) == nil)
|
||||
#expect(string.indexOfBracePair(beginIndex: string.index(2), pair: .ltgt) == nil)
|
||||
|
||||
XCTAssertNil(string.indexOfBracePair(endIndex: string.index(14), pair: pair, until: string.index(15)))
|
||||
XCTAssertNil(string.indexOfBracePair(beginIndex: string.index(4), pair: pair, until: string.index(2)))
|
||||
#expect(string.indexOfBracePair(endIndex: string.index(14), pair: pair, until: string.index(15)) == nil)
|
||||
#expect(string.indexOfBracePair(beginIndex: string.index(4), pair: pair, until: string.index(2)) == nil)
|
||||
}
|
||||
|
||||
|
||||
func testSamePair() {
|
||||
@Test func samePair() {
|
||||
|
||||
let string = "if ' foo ' 🐕 ' ' else ' '"
|
||||
let pair = BracePair("'", "'")
|
||||
|
||||
XCTAssertEqual(string.indexOfBracePair(endIndex: string.index(14), pair: pair), string.index(13))
|
||||
XCTAssertEqual(string.indexOfBracePair(beginIndex: string.index(4), pair: pair), string.index(9))
|
||||
XCTAssertNil(string.indexOfBracePair(endIndex: string.index(2), pair: pair))
|
||||
XCTAssertEqual(string.indexOfBracePair(beginIndex: string.index(2), pair: pair), string.index(3))
|
||||
#expect(string.indexOfBracePair(endIndex: string.index(14), pair: pair) == string.index(13))
|
||||
#expect(string.indexOfBracePair(beginIndex: string.index(4), pair: pair) == string.index(9))
|
||||
#expect(string.indexOfBracePair(endIndex: string.index(2), pair: pair) == nil)
|
||||
#expect(string.indexOfBracePair(beginIndex: string.index(2), pair: pair) == string.index(3))
|
||||
}
|
||||
|
||||
|
||||
func testScanner() {
|
||||
@Test func scan() {
|
||||
|
||||
let string = "def { foo {} | { bar } } "
|
||||
let pairs = BracePair.braces
|
||||
|
||||
XCTAssertNil(string.rangeOfEnclosingBracePair(at: string.range(1..<2), candidates: pairs))
|
||||
XCTAssertNil(string.rangeOfEnclosingBracePair(at: string.range(24..<24), candidates: pairs))
|
||||
#expect(string.rangeOfEnclosingBracePair(at: string.range(1..<2), candidates: pairs) == nil)
|
||||
#expect(string.rangeOfEnclosingBracePair(at: string.range(24..<24), candidates: pairs) == nil)
|
||||
|
||||
XCTAssertEqual(string.rangeOfEnclosingBracePair(at: string.range(13..<14), candidates: pairs), // = |
|
||||
string.range(4..<24))
|
||||
#expect(string.rangeOfEnclosingBracePair(at: string.range(13..<14), candidates: pairs) == string.range(4..<24)) // = |
|
||||
|
||||
XCTAssertEqual(string.rangeOfEnclosingBracePair(at: string.range(11..<11), candidates: pairs), // = {}
|
||||
string.range(10..<12))
|
||||
#expect(string.rangeOfEnclosingBracePair(at: string.range(11..<11), candidates: pairs) == string.range(10..<12)) // = {}
|
||||
}
|
||||
|
||||
|
||||
func testScannerWithEscape() {
|
||||
@Test func scanWithEscape() {
|
||||
|
||||
let pairs = BracePair.braces
|
||||
|
||||
let string1 = #"foo (\() )"#
|
||||
XCTAssertEqual(string1.rangeOfEnclosingBracePair(at: string1.range(7..<7), candidates: pairs),
|
||||
string1.range(4..<8))
|
||||
#expect(string1.rangeOfEnclosingBracePair(at: string1.range(7..<7), candidates: pairs) == string1.range(4..<8))
|
||||
|
||||
let string2 = #"foo (\\() )"#
|
||||
XCTAssertEqual(string2.rangeOfEnclosingBracePair(at: string2.range(8..<8), candidates: pairs),
|
||||
string2.range(7..<9))
|
||||
#expect(string2.rangeOfEnclosingBracePair(at: string2.range(8..<8), candidates: pairs) == string2.range(7..<9))
|
||||
|
||||
let string3 = #"foo (\\\() )"#
|
||||
XCTAssertEqual(string3.rangeOfEnclosingBracePair(at: string3.range(9..<9), candidates: pairs),
|
||||
string3.range(4..<10))
|
||||
#expect(string3.rangeOfEnclosingBracePair(at: string3.range(9..<9), candidates: pairs) == string3.range(4..<10))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2015-2023 1024jp
|
||||
// © 2015-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -24,131 +24,132 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import AppKit
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class CharacterInfoTests: XCTestCase {
|
||||
struct CharacterInfoTests {
|
||||
|
||||
// MARK: UTF32.CodeUnit Extension Tests
|
||||
|
||||
func testSingleSurrogate() {
|
||||
@Test func singleSurrogate() {
|
||||
|
||||
let character: UTF32.CodeUnit = 0xD83D
|
||||
|
||||
XCTAssertEqual(character.unicodeName, "<lead surrogate-D83D>")
|
||||
XCTAssertEqual(character.blockName, "High Surrogates")
|
||||
#expect(character.unicodeName == "<lead surrogate-D83D>")
|
||||
#expect(character.blockName == "High Surrogates")
|
||||
|
||||
XCTAssertNil(Unicode.Scalar(character))
|
||||
#expect(Unicode.Scalar(character) == nil)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UnicodeCharacter Tests
|
||||
|
||||
func testSingleChar() {
|
||||
@Test func singleChar() {
|
||||
|
||||
let unicode = Unicode.Scalar("あ")
|
||||
XCTAssertEqual(unicode.codePoint, "U+3042")
|
||||
XCTAssertFalse(unicode.isSurrogatePair)
|
||||
XCTAssertNil(unicode.surrogateCodePoints)
|
||||
XCTAssertEqual(unicode.name, "HIRAGANA LETTER A")
|
||||
XCTAssertEqual(unicode.blockName, "Hiragana")
|
||||
XCTAssertNotNil(unicode.localizedBlockName)
|
||||
#expect(unicode.codePoint == "U+3042")
|
||||
#expect(!unicode.isSurrogatePair)
|
||||
#expect(unicode.surrogateCodePoints == nil)
|
||||
#expect(unicode.name == "HIRAGANA LETTER A")
|
||||
#expect(unicode.blockName == "Hiragana")
|
||||
#expect(unicode.localizedBlockName != nil)
|
||||
}
|
||||
|
||||
|
||||
func testSurrogateEmoji() {
|
||||
@Test func surrogateEmoji() {
|
||||
|
||||
let unicode = Unicode.Scalar("😀")
|
||||
|
||||
XCTAssertEqual(unicode.codePoint, "U+1F600")
|
||||
XCTAssertTrue(unicode.isSurrogatePair)
|
||||
XCTAssertEqual(unicode.surrogateCodePoints?.lead, "U+D83D")
|
||||
XCTAssertEqual(unicode.surrogateCodePoints?.trail, "U+DE00")
|
||||
XCTAssertEqual(unicode.name, "GRINNING FACE")
|
||||
XCTAssertEqual(unicode.blockName, "Emoticons")
|
||||
XCTAssertNotNil(unicode.localizedBlockName)
|
||||
#expect(unicode.codePoint == "U+1F600")
|
||||
#expect(unicode.isSurrogatePair)
|
||||
#expect(unicode.surrogateCodePoints?.lead == "U+D83D")
|
||||
#expect(unicode.surrogateCodePoints?.trail == "U+DE00")
|
||||
#expect(unicode.name == "GRINNING FACE")
|
||||
#expect(unicode.blockName == "Emoticons")
|
||||
#expect(unicode.localizedBlockName != nil)
|
||||
}
|
||||
|
||||
|
||||
func testUnicodeBlockNameWithHyphen() {
|
||||
@Test func unicodeBlockNameWithHyphen() {
|
||||
|
||||
let character = Unicode.Scalar("﷽")
|
||||
|
||||
XCTAssertEqual(character.codePoint, "U+FDFD")
|
||||
XCTAssertEqual(character.name, "ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM")
|
||||
XCTAssertEqual(character.localizedBlockName, "Arabic Presentation Forms-A")
|
||||
#expect(character.codePoint == "U+FDFD")
|
||||
#expect(character.name == "ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM")
|
||||
#expect(character.localizedBlockName == "Arabic Presentation Forms-A")
|
||||
}
|
||||
|
||||
|
||||
func testUnicodeControlPictures() throws {
|
||||
@Test func unicodeControlPictures() throws {
|
||||
|
||||
// test NULL
|
||||
let nullCharacter = try XCTUnwrap(Unicode.Scalar(0x0000))
|
||||
let nullPictureCharacter = try XCTUnwrap(Unicode.Scalar(0x2400))
|
||||
XCTAssertEqual(nullCharacter.name, "NULL")
|
||||
XCTAssertEqual(nullPictureCharacter.name, "SYMBOL FOR NULL")
|
||||
XCTAssertEqual(nullCharacter.pictureRepresentation, nullPictureCharacter)
|
||||
let nullCharacter = try #require(Unicode.Scalar(0x0000))
|
||||
let nullPictureCharacter = try #require(Unicode.Scalar(0x2400))
|
||||
#expect(nullCharacter.name == "NULL")
|
||||
#expect(nullPictureCharacter.name == "SYMBOL FOR NULL")
|
||||
#expect(nullCharacter.pictureRepresentation == nullPictureCharacter)
|
||||
|
||||
// test SPACE
|
||||
let spaceCharacter = try XCTUnwrap(Unicode.Scalar(0x0020))
|
||||
let spacePictureCharacter = try XCTUnwrap(Unicode.Scalar(0x2420))
|
||||
XCTAssertEqual(spaceCharacter.name, "SPACE")
|
||||
XCTAssertEqual(spacePictureCharacter.name, "SYMBOL FOR SPACE")
|
||||
XCTAssertEqual(spaceCharacter.pictureRepresentation, spacePictureCharacter)
|
||||
let spaceCharacter = try #require(Unicode.Scalar(0x0020))
|
||||
let spacePictureCharacter = try #require(Unicode.Scalar(0x2420))
|
||||
#expect(spaceCharacter.name == "SPACE")
|
||||
#expect(spacePictureCharacter.name == "SYMBOL FOR SPACE")
|
||||
#expect(spaceCharacter.pictureRepresentation == spacePictureCharacter)
|
||||
|
||||
// test DELETE
|
||||
let deleteCharacter = try XCTUnwrap(Unicode.Scalar(NSDeleteCharacter))
|
||||
let deleteCharacter = try #require(Unicode.Scalar(NSDeleteCharacter))
|
||||
let deletePictureCharacter = Unicode.Scalar("␡")
|
||||
XCTAssertEqual(deleteCharacter.name, "DELETE")
|
||||
XCTAssertEqual(deletePictureCharacter.name, "SYMBOL FOR DELETE")
|
||||
XCTAssertEqual(deleteCharacter.pictureRepresentation, deletePictureCharacter)
|
||||
#expect(deleteCharacter.name == "DELETE")
|
||||
#expect(deletePictureCharacter.name == "SYMBOL FOR DELETE")
|
||||
#expect(deleteCharacter.pictureRepresentation == deletePictureCharacter)
|
||||
|
||||
// test one after the last C0 control character
|
||||
let exclamationCharacter = try XCTUnwrap(Unicode.Scalar(0x0021))
|
||||
XCTAssertEqual(exclamationCharacter.name, "EXCLAMATION MARK")
|
||||
XCTAssertNil(exclamationCharacter.pictureRepresentation)
|
||||
let exclamationCharacter = try #require(Unicode.Scalar(0x0021))
|
||||
#expect(exclamationCharacter.name == "EXCLAMATION MARK")
|
||||
#expect(exclamationCharacter.pictureRepresentation == nil)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - CharacterInfo Tests
|
||||
|
||||
func testSingleCharWithVSInfo() {
|
||||
@Test func singleCharacterWithVSInfo() {
|
||||
|
||||
let charInfo = CharacterInfo(character: "☺︎")
|
||||
|
||||
XCTAssertEqual(charInfo.character, "☺︎")
|
||||
XCTAssertFalse(charInfo.isComplex)
|
||||
XCTAssertEqual(charInfo.character.unicodeScalars.map(\.codePoint), ["U+263A", "U+FE0E"])
|
||||
XCTAssertEqual(charInfo.character.unicodeScalars.map(\.name), ["WHITE SMILING FACE", "VARIATION SELECTOR-15"])
|
||||
XCTAssertEqual(charInfo.localizedDescription, "WHITE SMILING FACE (Text Style)")
|
||||
#expect(charInfo.character == "☺︎")
|
||||
#expect(!charInfo.isComplex)
|
||||
#expect(charInfo.character.unicodeScalars.map(\.codePoint) == ["U+263A", "U+FE0E"])
|
||||
#expect(charInfo.character.unicodeScalars.map(\.name) == ["WHITE SMILING FACE", "VARIATION SELECTOR-15"])
|
||||
#expect(charInfo.localizedDescription == "WHITE SMILING FACE (Text Style)")
|
||||
}
|
||||
|
||||
|
||||
func testCombiningCharacterInfo() {
|
||||
@Test func combiningCharacterInfo() {
|
||||
|
||||
let charInfo = CharacterInfo(character: "1️⃣")
|
||||
|
||||
XCTAssertTrue(charInfo.isComplex)
|
||||
XCTAssertEqual(charInfo.character.unicodeScalars.map(\.codePoint), ["U+0031", "U+FE0F", "U+20E3"])
|
||||
XCTAssertEqual(charInfo.localizedDescription, "<a letter consisting of 3 characters>")
|
||||
#expect(charInfo.isComplex)
|
||||
#expect(charInfo.character.unicodeScalars.map(\.codePoint) == ["U+0031", "U+FE0F", "U+20E3"])
|
||||
#expect(charInfo.localizedDescription == "<a letter consisting of 3 characters>")
|
||||
}
|
||||
|
||||
|
||||
func testNationalIndicatorInfo() {
|
||||
@Test func nationalIndicatorInfo() {
|
||||
|
||||
let charInfo = CharacterInfo(character: "🇯🇵")
|
||||
|
||||
XCTAssertTrue(charInfo.isComplex)
|
||||
XCTAssertEqual(charInfo.character.unicodeScalars.map(\.codePoint), ["U+1F1EF", "U+1F1F5"])
|
||||
#expect(charInfo.isComplex)
|
||||
#expect(charInfo.character.unicodeScalars.map(\.codePoint) == ["U+1F1EF", "U+1F1F5"])
|
||||
}
|
||||
|
||||
|
||||
func testControlCharacterInfo() {
|
||||
@Test func controlCharacterInfo() {
|
||||
|
||||
let charInfo = CharacterInfo(character: " ")
|
||||
|
||||
XCTAssertEqual(charInfo.character, " ")
|
||||
XCTAssertEqual(charInfo.pictureCharacter, "␠")
|
||||
XCTAssertEqual(charInfo.character.unicodeScalars.map(\.name), ["SPACE"])
|
||||
#expect(charInfo.character == " ")
|
||||
#expect(charInfo.pictureCharacter == "␠")
|
||||
#expect(charInfo.character.unicodeScalars.map(\.name) == ["SPACE"])
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2017-2022 1024jp
|
||||
// © 2017-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -24,104 +24,100 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class CollectionTests: XCTestCase {
|
||||
struct CollectionTests {
|
||||
|
||||
func testAppendUnique() {
|
||||
@Test func appendUnique() {
|
||||
|
||||
var array = [0, 1, 2, 3, 4]
|
||||
|
||||
array.appendUnique(0, maximum: 5)
|
||||
XCTAssertEqual(array, [1, 2, 3, 4, 0])
|
||||
#expect(array == [1, 2, 3, 4, 0])
|
||||
|
||||
array.appendUnique(6, maximum: 5)
|
||||
XCTAssertEqual(array, [2, 3, 4, 0, 6])
|
||||
#expect(array == [2, 3, 4, 0, 6])
|
||||
|
||||
array.appendUnique(7, maximum: 6)
|
||||
XCTAssertEqual(array, [2, 3, 4, 0, 6, 7])
|
||||
#expect(array == [2, 3, 4, 0, 6, 7])
|
||||
|
||||
array.appendUnique(6, maximum: 3)
|
||||
XCTAssertEqual(array, [0, 7, 6])
|
||||
#expect(array == [0, 7, 6])
|
||||
}
|
||||
|
||||
|
||||
func testCount() {
|
||||
@Test func count() {
|
||||
|
||||
XCTAssertEqual([1, 2, 0, -1, 3].count(where: { $0 > 0 }), 3)
|
||||
XCTAssertEqual([0, 1, 2, 0, -1].count(where: { $0 > 0 }), 2)
|
||||
XCTAssertEqual([1, 2, 3, 4, 5].count(where: { $0 > 0 }), 5)
|
||||
#expect([1, 2, 0, -1, 3].count(where: { $0 > 0 }) == 3)
|
||||
#expect([0, 1, 2, 0, -1].count(where: { $0 > 0 }) == 2)
|
||||
#expect([1, 2, 3, 4, 5].count(where: { $0 > 0 }) == 5)
|
||||
|
||||
XCTAssertEqual([1, 2, 0, -1, 3].countPrefix(while: { $0 > 0 }), 2)
|
||||
XCTAssertEqual([0, 1, 2, 0, -1].countPrefix(while: { $0 > 0 }), 0)
|
||||
XCTAssertEqual([1, 2, 3, 4, 5].countPrefix(while: { $0 > 0 }), 5)
|
||||
#expect([1, 2, 0, -1, 3].countPrefix(while: { $0 > 0 }) == 2)
|
||||
#expect([0, 1, 2, 0, -1].countPrefix(while: { $0 > 0 }) == 0)
|
||||
#expect([1, 2, 3, 4, 5].countPrefix(while: { $0 > 0 }) == 5)
|
||||
}
|
||||
|
||||
|
||||
func testCountComparison() {
|
||||
@Test func compareCount() {
|
||||
|
||||
XCTAssertEqual("".compareCount(with: 0), .equal)
|
||||
XCTAssertEqual("".compareCount(with: 1), .less)
|
||||
#expect("".compareCount(with: 0) == .equal)
|
||||
#expect("".compareCount(with: 1) == .less)
|
||||
|
||||
XCTAssertEqual("a".compareCount(with: 1), .equal)
|
||||
XCTAssertEqual("🐕".compareCount(with: 1), .equal)
|
||||
XCTAssertEqual("🐕🦺".compareCount(with: 1), .equal)
|
||||
#expect("a".compareCount(with: 1) == .equal)
|
||||
#expect("🐕".compareCount(with: 1) == .equal)
|
||||
#expect("🐕🦺".compareCount(with: 1) == .equal)
|
||||
|
||||
XCTAssertEqual("🐶🐱".compareCount(with: 3), .less)
|
||||
XCTAssertEqual("🐶🐱".compareCount(with: 2), .equal)
|
||||
XCTAssertEqual("🐶🐱".compareCount(with: 1), .greater)
|
||||
#expect("🐶🐱".compareCount(with: 3) == .less)
|
||||
#expect("🐶🐱".compareCount(with: 2) == .equal)
|
||||
#expect("🐶🐱".compareCount(with: 1) == .greater)
|
||||
}
|
||||
|
||||
|
||||
func testKeyMapping() {
|
||||
@Test func mapKeys() {
|
||||
|
||||
let dict = [1: 1, 2: 2, 3: 3]
|
||||
let mapped = dict.mapKeys { String($0 * 10) }
|
||||
|
||||
XCTAssertEqual(mapped, ["10": 1, "20": 2, "30": 3])
|
||||
#expect(mapped == ["10": 1, "20": 2, "30": 3])
|
||||
}
|
||||
|
||||
|
||||
func testRawRepresentable() {
|
||||
@Test func rawRepresentable() {
|
||||
|
||||
enum TestKey: String {
|
||||
case dog, cat, cow
|
||||
}
|
||||
var dict = ["dog": "🐶", "cat": "🐱"]
|
||||
|
||||
XCTAssertEqual(dict[TestKey.dog], dict[TestKey.dog.rawValue])
|
||||
XCTAssertNil(dict[TestKey.cow])
|
||||
#expect(dict[TestKey.dog] == dict[TestKey.dog.rawValue])
|
||||
#expect(dict[TestKey.cow] == nil)
|
||||
|
||||
dict[TestKey.cow] = "🐮"
|
||||
XCTAssertEqual(dict[TestKey.cow], "🐮")
|
||||
#expect(dict[TestKey.cow] == "🐮")
|
||||
}
|
||||
|
||||
|
||||
func testSorting() {
|
||||
@Test(arguments: 0..<10) func sort(index: Int) {
|
||||
|
||||
for _ in 0..<10 {
|
||||
var array: [Int] = (0..<10).map { _ in .random(in: 0..<100) }
|
||||
let sorted = array.sorted { $0 < $1 }
|
||||
|
||||
XCTAssertEqual(array.sorted(), sorted)
|
||||
|
||||
array.sort()
|
||||
XCTAssertEqual(array, sorted)
|
||||
}
|
||||
var array: [Int] = (0..<10).map { _ in .random(in: 0..<100) }
|
||||
let sorted = array.sorted { $0 < $1 }
|
||||
|
||||
#expect(array.sorted() == sorted)
|
||||
|
||||
array.sort()
|
||||
#expect(array == sorted)
|
||||
}
|
||||
|
||||
|
||||
func testBinarySearch() {
|
||||
@Test(arguments: 0..<10) func binarySearch(index: Int) {
|
||||
|
||||
let array = (0..<20).map { _ in Int.random(in: 0..<100) }.sorted()
|
||||
|
||||
for _ in 0..<10 {
|
||||
let array = (0..<20).map { _ in Int.random(in: 0..<100) }.sorted()
|
||||
|
||||
for _ in 0..<10 {
|
||||
let index = Int.random(in: 0..<100)
|
||||
XCTAssertEqual(array.binarySearchedFirstIndex(where: { $0 > index }),
|
||||
array.firstIndex(where: { $0 > index }))
|
||||
}
|
||||
let index = Int.random(in: 0..<100)
|
||||
#expect(array.binarySearchedFirstIndex(where: { $0 > index }) ==
|
||||
array.firstIndex(where: { $0 > index }))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,26 +23,27 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class ComparableTests: XCTestCase {
|
||||
struct ComparableTests {
|
||||
|
||||
func testClamp() {
|
||||
@Test func clamp() {
|
||||
|
||||
XCTAssertEqual((-2).clamped(to: -10...10), -2)
|
||||
XCTAssertEqual(5.clamped(to: 6...10), 6)
|
||||
XCTAssertEqual(20.clamped(to: 6...10), 10)
|
||||
#expect((-2).clamped(to: -10...10) == -2)
|
||||
#expect(5.clamped(to: 6...10) == 6)
|
||||
#expect(20.clamped(to: 6...10) == 10)
|
||||
}
|
||||
|
||||
|
||||
func testBoolComparison() {
|
||||
@Test func compareBool() {
|
||||
|
||||
XCTAssertEqual([false, true, false, true, false].sorted(), [true, true, false, false, false])
|
||||
#expect([false, true, false, true, false].sorted() == [true, true, false, false, false])
|
||||
}
|
||||
|
||||
|
||||
func testBoolItemComparison() {
|
||||
@Test func compareBoolItem() {
|
||||
|
||||
struct Item: Equatable {
|
||||
|
||||
@ -58,7 +59,7 @@ final class ComparableTests: XCTestCase {
|
||||
Item(id: 4, bool: true),
|
||||
]
|
||||
|
||||
XCTAssertEqual(items.sorted(\.bool), [
|
||||
#expect(items.sorted(\.bool) == [
|
||||
Item(id: 1, bool: true),
|
||||
Item(id: 2, bool: true),
|
||||
Item(id: 4, bool: true),
|
||||
@ -66,7 +67,7 @@ final class ComparableTests: XCTestCase {
|
||||
Item(id: 3, bool: false),
|
||||
])
|
||||
|
||||
XCTAssertEqual(items.sorted(using: [KeyPathComparator(\.bool)]), [
|
||||
#expect(items.sorted(using: [KeyPathComparator(\.bool)]) == [
|
||||
Item(id: 1, bool: true),
|
||||
Item(id: 2, bool: true),
|
||||
Item(id: 4, bool: true),
|
||||
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2020 1024jp
|
||||
// © 2020-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -23,71 +23,55 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class DebouncerTests: XCTestCase {
|
||||
struct DebouncerTests {
|
||||
|
||||
func testDebounce() {
|
||||
@Test func debounce() async throws {
|
||||
|
||||
let expectation = self.expectation(description: "Debouncer executed")
|
||||
let waitingExpectation = self.expectation(description: "Debouncer waiting")
|
||||
waitingExpectation.isInverted = true
|
||||
|
||||
var value = 0
|
||||
let debouncer = Debouncer(delay: .seconds(0.5)) {
|
||||
value += 1
|
||||
expectation.fulfill()
|
||||
waitingExpectation.fulfill()
|
||||
try await confirmation("Debouncer executed", expectedCount: 1) { confirm in
|
||||
let debouncer = Debouncer(delay: .seconds(0.5)) {
|
||||
confirm()
|
||||
}
|
||||
|
||||
debouncer.schedule()
|
||||
debouncer.schedule()
|
||||
|
||||
try await Task.sleep(for: .seconds(1))
|
||||
}
|
||||
|
||||
XCTAssertEqual(value, 0)
|
||||
|
||||
debouncer.schedule()
|
||||
debouncer.schedule()
|
||||
|
||||
self.wait(for: [waitingExpectation], timeout: 0.1)
|
||||
|
||||
XCTAssertEqual(value, 0)
|
||||
|
||||
self.wait(for: [expectation], timeout: 0.5)
|
||||
|
||||
XCTAssertEqual(value, 1)
|
||||
}
|
||||
|
||||
|
||||
func testImidiateFire() {
|
||||
@Test func immediateFire() {
|
||||
|
||||
var value = 0
|
||||
let debouncer = Debouncer {
|
||||
value += 1
|
||||
}
|
||||
|
||||
XCTAssertEqual(0, value)
|
||||
#expect(0 == value)
|
||||
|
||||
debouncer.fireNow()
|
||||
XCTAssertEqual(value, 0, "The action is performed only when scheduled.")
|
||||
#expect(value == 0, "The action is performed only when scheduled.")
|
||||
|
||||
debouncer.schedule()
|
||||
XCTAssertEqual(value, 0)
|
||||
#expect(value == 0)
|
||||
|
||||
debouncer.fireNow()
|
||||
XCTAssertEqual(value, 1, "The scheduled action must be performed immediately.")
|
||||
#expect(value == 1, "The scheduled action must be performed immediately.")
|
||||
}
|
||||
|
||||
|
||||
func testCancellation() {
|
||||
@Test func cancel() async {
|
||||
|
||||
let expectation = self.expectation(description: "Debouncer cancelled")
|
||||
expectation.isInverted = true
|
||||
|
||||
let debouncer = Debouncer {
|
||||
expectation.fulfill()
|
||||
await confirmation("Debouncer cancelled", expectedCount: 0) { confirm in
|
||||
let debouncer = Debouncer {
|
||||
confirm()
|
||||
}
|
||||
|
||||
debouncer.schedule()
|
||||
debouncer.cancel()
|
||||
}
|
||||
|
||||
debouncer.schedule()
|
||||
debouncer.cancel()
|
||||
|
||||
self.waitForExpectations(timeout: 1)
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2023 1024jp
|
||||
// © 2023-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -23,13 +23,14 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
import Combine
|
||||
import XCTest
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class EditedRangeSetTests: XCTestCase {
|
||||
struct EditedRangeSetTests {
|
||||
|
||||
func testRangeSet() throws {
|
||||
@Test func rangeSet() throws {
|
||||
|
||||
// abcdefg
|
||||
var set = EditedRangeSet()
|
||||
@ -37,35 +38,35 @@ final class EditedRangeSetTests: XCTestCase {
|
||||
// ab|0000|efg
|
||||
// .replaceCharacters(in: NSRange(2..<3), with: "0000")
|
||||
set.append(editedRange: NSRange(location: 2, length: 4), changeInLength: 2)
|
||||
XCTAssertEqual(set.ranges, [NSRange(location: 2, length: 4)])
|
||||
#expect(set.ranges == [NSRange(location: 2, length: 4)])
|
||||
|
||||
// ab0000e|g
|
||||
// .replaceCharacters(in: NSRange(7..<8), with: "")
|
||||
set.append(editedRange: NSRange(location: 7, length: 0), changeInLength: -1)
|
||||
XCTAssertEqual(set.ranges, [NSRange(location: 2, length: 4),
|
||||
NSRange(location: 7, length: 0)])
|
||||
#expect(set.ranges == [NSRange(location: 2, length: 4),
|
||||
NSRange(location: 7, length: 0)])
|
||||
|
||||
// ab0|0eg
|
||||
// .replaceCharacters(in: NSRange(3..<5), with: "")
|
||||
set.append(editedRange: NSRange(location: 3, length: 0), changeInLength: -2)
|
||||
XCTAssertEqual(set.ranges, [NSRange(location: 2, length: 2),
|
||||
NSRange(location: 5, length: 0)])
|
||||
#expect(set.ranges == [NSRange(location: 2, length: 2),
|
||||
NSRange(location: 5, length: 0)])
|
||||
|
||||
// a|1|b00eg
|
||||
// .replaceCharacters(in: NSRange(1..<1), with: "1")
|
||||
set.append(editedRange: NSRange(location: 1, length: 1), changeInLength: 1)
|
||||
XCTAssertEqual(set.ranges, [NSRange(location: 1, length: 1),
|
||||
NSRange(location: 3, length: 2),
|
||||
NSRange(location: 6, length: 0)])
|
||||
#expect(set.ranges == [NSRange(location: 1, length: 1),
|
||||
NSRange(location: 3, length: 2),
|
||||
NSRange(location: 6, length: 0)])
|
||||
|
||||
set.clear()
|
||||
XCTAssert(set.ranges.isEmpty)
|
||||
#expect(set.ranges.isEmpty)
|
||||
}
|
||||
|
||||
|
||||
func testUnion() throws {
|
||||
@Test func union() throws {
|
||||
|
||||
XCTAssertEqual(NSRange(2..<3).union(NSRange(3..<4)), NSRange(2..<4))
|
||||
#expect(NSRange(2..<3).union(NSRange(3..<4)) == NSRange(2..<4))
|
||||
|
||||
let textStorage = NSTextStorage("abcdefghij")
|
||||
var set = EditedRangeSet()
|
||||
@ -74,22 +75,22 @@ final class EditedRangeSetTests: XCTestCase {
|
||||
set.append(editedRange: NSRange(location: 2, length: 2), changeInLength: 0)
|
||||
textStorage.replaceCharacters(in: NSRange(location: 6, length: 2), with: "00")
|
||||
set.append(editedRange: NSRange(location: 6, length: 2), changeInLength: 0)
|
||||
XCTAssertEqual(textStorage.string, "ab00ef00ij")
|
||||
XCTAssertEqual(set.ranges, [NSRange(location: 2, length: 2), NSRange(location: 6, length: 2)])
|
||||
#expect(textStorage.string == "ab00ef00ij")
|
||||
#expect(set.ranges == [NSRange(location: 2, length: 2), NSRange(location: 6, length: 2)])
|
||||
|
||||
textStorage.replaceCharacters(in: NSRange(location: 3, length: 4), with: "11")
|
||||
set.append(editedRange: NSRange(location: 3, length: 2), changeInLength: -2)
|
||||
XCTAssertEqual(textStorage.string, "ab0110ij")
|
||||
XCTAssertEqual(set.ranges, [NSRange(location: 2, length: 4)])
|
||||
#expect(textStorage.string == "ab0110ij")
|
||||
#expect(set.ranges == [NSRange(location: 2, length: 4)])
|
||||
|
||||
textStorage.replaceCharacters(in: NSRange(location: 1, length: 3), with: "22")
|
||||
set.append(editedRange: NSRange(location: 1, length: 2), changeInLength: -1)
|
||||
XCTAssertEqual(textStorage.string, "a2210ij")
|
||||
XCTAssertEqual(set.ranges, [NSRange(location: 1, length: 4)])
|
||||
#expect(textStorage.string == "a2210ij")
|
||||
#expect(set.ranges == [NSRange(location: 1, length: 4)])
|
||||
}
|
||||
|
||||
|
||||
func testJoin() throws {
|
||||
@Test func join() throws {
|
||||
|
||||
var set = EditedRangeSet()
|
||||
|
||||
@ -98,38 +99,35 @@ final class EditedRangeSetTests: XCTestCase {
|
||||
set.append(editedRange: NSRange(location: 0, length: 2), changeInLength: 0)
|
||||
set.append(editedRange: NSRange(location: 2, length: 2), changeInLength: 0)
|
||||
|
||||
XCTAssertEqual(set.ranges, [NSRange(location: 0, length: 6)])
|
||||
#expect(set.ranges == [NSRange(location: 0, length: 6)])
|
||||
}
|
||||
|
||||
|
||||
func testStorageTest() async throws {
|
||||
@Test func testStorage() async throws {
|
||||
|
||||
let textStorage = NSTextStorage("abcdefg")
|
||||
var set = EditedRangeSet()
|
||||
|
||||
let expectation = self.expectation(description: "UserDefaults observation for normal key")
|
||||
expectation.expectedFulfillmentCount = 4
|
||||
|
||||
let observer = NotificationCenter.default.publisher(for: NSTextStorage.didProcessEditingNotification, object: textStorage)
|
||||
.map { $0.object as! NSTextStorage }
|
||||
.filter { $0.editedMask.contains(.editedCharacters) }
|
||||
.sink { storage in
|
||||
set.append(editedRange: storage.editedRange, changeInLength: storage.changeInLength)
|
||||
expectation.fulfill()
|
||||
}
|
||||
|
||||
textStorage.replaceCharacters(in: NSRange(2..<4), with: "0000")
|
||||
textStorage.replaceCharacters(in: NSRange(7..<8), with: "")
|
||||
textStorage.replaceCharacters(in: NSRange(3..<5), with: "")
|
||||
textStorage.replaceCharacters(in: NSRange(1..<1), with: "1")
|
||||
|
||||
await self.fulfillment(of: [expectation], timeout: 2)
|
||||
|
||||
XCTAssertEqual(textStorage.string, "a1b00eg")
|
||||
XCTAssertEqual(set.ranges, [NSRange(location: 1, length: 1),
|
||||
NSRange(location: 3, length: 2),
|
||||
NSRange(location: 6, length: 0)])
|
||||
|
||||
observer.cancel()
|
||||
await confirmation("UserDefaults observation for normal key", expectedCount: 4) { confirm in
|
||||
let observer = NotificationCenter.default.publisher(for: NSTextStorage.didProcessEditingNotification, object: textStorage)
|
||||
.map { $0.object as! NSTextStorage }
|
||||
.filter { $0.editedMask.contains(.editedCharacters) }
|
||||
.sink { storage in
|
||||
set.append(editedRange: storage.editedRange, changeInLength: storage.changeInLength)
|
||||
confirm()
|
||||
}
|
||||
|
||||
textStorage.replaceCharacters(in: NSRange(2..<4), with: "0000")
|
||||
textStorage.replaceCharacters(in: NSRange(7..<8), with: "")
|
||||
textStorage.replaceCharacters(in: NSRange(3..<5), with: "")
|
||||
textStorage.replaceCharacters(in: NSRange(1..<1), with: "1")
|
||||
|
||||
#expect(textStorage.string == "a1b00eg")
|
||||
#expect(set.ranges == [NSRange(location: 1, length: 1),
|
||||
NSRange(location: 3, length: 2),
|
||||
NSRange(location: 6, length: 0)])
|
||||
|
||||
observer.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,10 +23,11 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import AppKit
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class EditorCounterTests: XCTestCase {
|
||||
final class EditorCounterTests {
|
||||
|
||||
@MainActor final class Provider: TextViewProvider {
|
||||
|
||||
@ -47,7 +48,7 @@ final class EditorCounterTests: XCTestCase {
|
||||
Both are 👍🏼.
|
||||
"""
|
||||
|
||||
@MainActor func testNoRequiredInfo() throws {
|
||||
@MainActor @Test func noRequiredInfo() throws {
|
||||
|
||||
let provider = Provider(string: self.testString, selectedRange: NSRange(0..<3))
|
||||
|
||||
@ -56,16 +57,16 @@ final class EditorCounterTests: XCTestCase {
|
||||
counter.invalidateContent()
|
||||
counter.invalidateSelection()
|
||||
|
||||
XCTAssertNil(counter.result.lines.entire)
|
||||
XCTAssertNil(counter.result.characters.entire)
|
||||
XCTAssertNil(counter.result.words.entire)
|
||||
XCTAssertNil(counter.result.location)
|
||||
XCTAssertNil(counter.result.line)
|
||||
XCTAssertNil(counter.result.column)
|
||||
#expect(counter.result.lines.entire == nil)
|
||||
#expect(counter.result.characters.entire == nil)
|
||||
#expect(counter.result.words.entire == nil)
|
||||
#expect(counter.result.location == nil)
|
||||
#expect(counter.result.line == nil)
|
||||
#expect(counter.result.column == nil)
|
||||
}
|
||||
|
||||
|
||||
@MainActor func testAllRequiredInfo() throws {
|
||||
@MainActor @Test func allRequiredInfo() throws {
|
||||
|
||||
let provider = Provider(string: self.testString, selectedRange: NSRange(11..<21))
|
||||
|
||||
@ -75,21 +76,21 @@ final class EditorCounterTests: XCTestCase {
|
||||
counter.invalidateContent()
|
||||
counter.invalidateSelection()
|
||||
|
||||
// XCTAssertEqual(counter.result.lines.entire, 3)
|
||||
// XCTAssertEqual(counter.result.characters.entire, 31)
|
||||
// XCTAssertEqual(counter.result.words.entire, 6)
|
||||
// #expect(counter.result.lines.entire == 3)
|
||||
// #expect(counter.result.characters.entire == 31)
|
||||
// #expect(counter.result.words.entire == 6)
|
||||
|
||||
// XCTAssertEqual(counter.result.characters.selected, 9)
|
||||
// XCTAssertEqual(counter.result.lines.selected, 1)
|
||||
// XCTAssertEqual(counter.result.words.selected, 2)
|
||||
// #expect(counter.result.characters.selected == 9)
|
||||
// #expect(counter.result.lines.selected == 1)
|
||||
// #expect(counter.result.words.selected == 2)
|
||||
|
||||
// XCTAssertEqual(counter.result.location, 10)
|
||||
// XCTAssertEqual(counter.result.column, 0)
|
||||
// XCTAssertEqual(counter.result.line, 2)
|
||||
// #expect(counter.result.location == 10)
|
||||
// #expect(counter.result.column == 0)
|
||||
// #expect(counter.result.line == 2)
|
||||
}
|
||||
|
||||
|
||||
@MainActor func testWholeTextSkip() throws {
|
||||
@MainActor @Test func skipWholeText() throws {
|
||||
|
||||
let provider = Provider(string: self.testString, selectedRange: NSRange(11..<21))
|
||||
|
||||
@ -98,21 +99,21 @@ final class EditorCounterTests: XCTestCase {
|
||||
counter.updatesAll = true
|
||||
counter.invalidateSelection()
|
||||
|
||||
XCTAssertNil(counter.result.lines.entire)
|
||||
XCTAssertNil(counter.result.characters.entire)
|
||||
XCTAssertNil(counter.result.words.entire)
|
||||
#expect(counter.result.lines.entire == nil)
|
||||
#expect(counter.result.characters.entire == nil)
|
||||
#expect(counter.result.words.entire == nil)
|
||||
|
||||
// XCTAssertEqual(counter.result.lines.selected, 1)
|
||||
// XCTAssertEqual(counter.result.characters.selected, 9)
|
||||
// XCTAssertEqual(counter.result.words.selected, 2)
|
||||
// #expect(counter.result.lines.selected == 1)
|
||||
// #expect(counter.result.characters.selected == 9)
|
||||
// #expect(counter.result.words.selected == 2)
|
||||
|
||||
// XCTAssertEqual(counter.result.location, 10)
|
||||
// XCTAssertEqual(counter.result.column, 0)
|
||||
// XCTAssertEqual(counter.result.line, 2)
|
||||
// #expect(counter.result.location == 10)
|
||||
// #expect(counter.result.column == 0)
|
||||
// #expect(counter.result.line == 2)
|
||||
}
|
||||
|
||||
|
||||
@MainActor func testCRLF() throws {
|
||||
@MainActor @Test func crlf() throws {
|
||||
|
||||
let provider = Provider(string: "a\r\nb", selectedRange: NSRange(1..<4))
|
||||
|
||||
@ -122,33 +123,33 @@ final class EditorCounterTests: XCTestCase {
|
||||
counter.invalidateContent()
|
||||
counter.invalidateSelection()
|
||||
|
||||
// XCTAssertEqual(counter.result.lines.entire, 2)
|
||||
// XCTAssertEqual(counter.result.characters.entire, 3)
|
||||
// XCTAssertEqual(counter.result.words.entire, 2)
|
||||
// #expect(counter.result.lines.entire == 2)
|
||||
// #expect(counter.result.characters.entire == 3)
|
||||
// #expect(counter.result.words.entire == 2)
|
||||
|
||||
// XCTAssertEqual(counter.result.lines.selected, 2)
|
||||
// XCTAssertEqual(counter.result.characters.selected, 2)
|
||||
// XCTAssertEqual(counter.result.words.selected, 1)
|
||||
// #expect(counter.result.lines.selected == 2)
|
||||
// #expect(counter.result.characters.selected == 2)
|
||||
// #expect(counter.result.words.selected == 1)
|
||||
|
||||
// XCTAssertEqual(counter.result.location, 1)
|
||||
// XCTAssertEqual(counter.result.column, 1)
|
||||
// XCTAssertEqual(counter.result.line, 1)
|
||||
// #expect(counter.result.location == 1)
|
||||
// #expect(counter.result.column == 1)
|
||||
// #expect(counter.result.line == 1)
|
||||
}
|
||||
|
||||
|
||||
func testEditorCountFormatting() {
|
||||
@Test func formatEditorCount() {
|
||||
|
||||
var count = EditorCount()
|
||||
|
||||
XCTAssertNil(count.formatted)
|
||||
#expect(count.formatted == nil)
|
||||
|
||||
count.entire = 1000
|
||||
XCTAssertEqual(count.formatted, "1,000")
|
||||
#expect(count.formatted == "1,000")
|
||||
|
||||
count.selected = 100
|
||||
XCTAssertEqual(count.formatted, "1,000 (100)")
|
||||
#expect(count.formatted == "1,000 (100)")
|
||||
|
||||
count.entire = nil
|
||||
XCTAssertNil(count.formatted)
|
||||
#expect(count.formatted == nil)
|
||||
}
|
||||
}
|
||||
|
@ -24,54 +24,52 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class EncodingDetectionTests: XCTestCase {
|
||||
final class EncodingDetectionTests {
|
||||
|
||||
private lazy var bundle = Bundle(for: type(of: self))
|
||||
|
||||
|
||||
func testUTF8BOM() throws {
|
||||
@Test func utf8BOM() throws {
|
||||
|
||||
// -> String(data:encoding:) preserves BOM since Swift 5 (2019-03)
|
||||
// cf. https://bugs.swift.org/browse/SR-10173
|
||||
let data = try self.dataForFileName("UTF-8 BOM")
|
||||
XCTAssertEqual(String(decoding: data, as: UTF8.self), "\u{FEFF}0")
|
||||
XCTAssertEqual(String(bomCapableData: data, encoding: .utf8), "0")
|
||||
#expect(String(decoding: data, as: UTF8.self) == "\u{FEFF}0")
|
||||
#expect(String(bomCapableData: data, encoding: .utf8) == "0")
|
||||
|
||||
var encoding: String.Encoding?
|
||||
let string = try self.encodedStringForFileName("UTF-8 BOM", usedEncoding: &encoding)
|
||||
|
||||
XCTAssertEqual(string, "0")
|
||||
XCTAssertEqual(encoding, .utf8)
|
||||
#expect(string == "0")
|
||||
#expect(encoding == .utf8)
|
||||
|
||||
XCTAssertEqual(String(bomCapableData: Data(Unicode.BOM.utf8.sequence), encoding: .utf8), "")
|
||||
XCTAssertEqual(String(bomCapableData: Data(), encoding: .utf8), "")
|
||||
#expect(String(bomCapableData: Data(Unicode.BOM.utf8.sequence), encoding: .utf8)?.isEmpty == true)
|
||||
#expect(String(bomCapableData: Data(), encoding: .utf8)?.isEmpty == true)
|
||||
}
|
||||
|
||||
|
||||
func testUTF16() throws {
|
||||
@Test func utf16() throws {
|
||||
|
||||
var encoding: String.Encoding?
|
||||
let string = try self.encodedStringForFileName("UTF-16", usedEncoding: &encoding)
|
||||
|
||||
XCTAssertEqual(string, "0")
|
||||
XCTAssertEqual(encoding, .utf16)
|
||||
#expect(string == "0")
|
||||
#expect(encoding == .utf16)
|
||||
}
|
||||
|
||||
|
||||
func testUTF32() throws {
|
||||
@Test func utf32() throws {
|
||||
|
||||
var encoding: String.Encoding?
|
||||
let string = try self.encodedStringForFileName("UTF-32", usedEncoding: &encoding)
|
||||
|
||||
XCTAssertEqual(string, "0")
|
||||
XCTAssertEqual(encoding, .utf32)
|
||||
#expect(string == "0")
|
||||
#expect(encoding == .utf32)
|
||||
}
|
||||
|
||||
|
||||
func testISO2022() throws {
|
||||
@Test func iso2022() throws {
|
||||
|
||||
let data = try self.dataForFileName("ISO 2022-JP")
|
||||
let encodings: [String.Encoding] = [.iso2022JP, .utf16]
|
||||
@ -79,24 +77,24 @@ final class EncodingDetectionTests: XCTestCase {
|
||||
var encoding: String.Encoding?
|
||||
let string = try String(data: data, suggestedEncodings: encodings, usedEncoding: &encoding)
|
||||
|
||||
XCTAssertEqual(string, "dog犬")
|
||||
XCTAssertEqual(encoding, .iso2022JP)
|
||||
#expect(string == "dog犬")
|
||||
#expect(encoding == .iso2022JP)
|
||||
}
|
||||
|
||||
|
||||
func testUTF8() throws {
|
||||
@Test func utf8() throws {
|
||||
|
||||
let data = try self.dataForFileName("UTF-8")
|
||||
|
||||
var encoding: String.Encoding?
|
||||
XCTAssertThrowsError(try String(data: data, suggestedEncodings: [], usedEncoding: &encoding)) { error in
|
||||
XCTAssertEqual(error as? CocoaError, CocoaError(.fileReadUnknownStringEncoding))
|
||||
#expect(throws: CocoaError(.fileReadUnknownStringEncoding)) {
|
||||
try String(data: data, suggestedEncodings: [], usedEncoding: &encoding)
|
||||
}
|
||||
XCTAssertNil(encoding)
|
||||
#expect(encoding == nil)
|
||||
}
|
||||
|
||||
|
||||
func testSuggestedEncoding() throws {
|
||||
@Test func suggestedEncoding() throws {
|
||||
|
||||
let data = try self.dataForFileName("UTF-8")
|
||||
|
||||
@ -104,66 +102,66 @@ final class EncodingDetectionTests: XCTestCase {
|
||||
let invalidEncoding = String.Encoding(cfEncoding: kCFStringEncodingInvalidId)
|
||||
let string = try String(data: data, suggestedEncodings: [invalidEncoding, .utf8], usedEncoding: &encoding)
|
||||
|
||||
XCTAssertEqual(string, "0")
|
||||
XCTAssertEqual(encoding, .utf8)
|
||||
#expect(string == "0")
|
||||
#expect(encoding == .utf8)
|
||||
}
|
||||
|
||||
|
||||
func testEmptyData() {
|
||||
@Test func emptyData() {
|
||||
|
||||
let data = Data()
|
||||
|
||||
var encoding: String.Encoding?
|
||||
var string: String?
|
||||
|
||||
XCTAssertThrowsError(string = try String(data: data, suggestedEncodings: [], usedEncoding: &encoding)) { error in
|
||||
XCTAssertEqual(error as? CocoaError, CocoaError(.fileReadUnknownStringEncoding))
|
||||
#expect(throws: CocoaError(.fileReadUnknownStringEncoding)) {
|
||||
string = try String(data: data, suggestedEncodings: [], usedEncoding: &encoding)
|
||||
}
|
||||
|
||||
XCTAssertNil(string)
|
||||
XCTAssertNil(encoding)
|
||||
XCTAssertFalse(data.starts(with: Unicode.BOM.utf8.sequence))
|
||||
#expect(string == nil)
|
||||
#expect(encoding == nil)
|
||||
#expect(!data.starts(with: Unicode.BOM.utf8.sequence))
|
||||
}
|
||||
|
||||
|
||||
func testUTF8BOMData() throws {
|
||||
@Test func utf8BOMData() throws {
|
||||
|
||||
let withBOMData = try self.dataForFileName("UTF-8 BOM")
|
||||
XCTAssertTrue(withBOMData.starts(with: Unicode.BOM.utf8.sequence))
|
||||
#expect(withBOMData.starts(with: Unicode.BOM.utf8.sequence))
|
||||
|
||||
let data = try self.dataForFileName("UTF-8")
|
||||
XCTAssertFalse(data.starts(with: Unicode.BOM.utf8.sequence))
|
||||
#expect(!data.starts(with: Unicode.BOM.utf8.sequence))
|
||||
}
|
||||
|
||||
|
||||
func testEncodingDeclarationScan() {
|
||||
@Test func scanEncodingDeclaration() throws {
|
||||
|
||||
let string = "<meta charset=\"Shift_JIS\"/>"
|
||||
XCTAssertNil(string.scanEncodingDeclaration(upTo: 16))
|
||||
XCTAssertEqual(string.scanEncodingDeclaration(upTo: 128), String.Encoding(cfEncodings: .shiftJIS))
|
||||
#expect(string.scanEncodingDeclaration(upTo: 16) == nil)
|
||||
#expect(string.scanEncodingDeclaration(upTo: 128) == String.Encoding(cfEncodings: .shiftJIS))
|
||||
|
||||
XCTAssertEqual("<meta charset=\"utf-8\"/>".scanEncodingDeclaration(upTo: 128), .utf8)
|
||||
#expect("<meta charset=\"utf-8\"/>".scanEncodingDeclaration(upTo: 128) == .utf8)
|
||||
|
||||
// Swift.Regex with non-simple word boundaries never returns when the given string contains a specific pattern of letters (2023-12 on Swift 5.9).
|
||||
XCTAssertNil("タマゴ,1,".scanEncodingDeclaration(upTo: 128))
|
||||
XCTAssertNil(try /\ba/.wordBoundaryKind(.simple).firstMatch(in: "タマゴ,1,"))
|
||||
#expect("タマゴ,1,".scanEncodingDeclaration(upTo: 128) == nil)
|
||||
#expect(try /\ba/.wordBoundaryKind(.simple).firstMatch(in: "タマゴ,1,") == nil)
|
||||
}
|
||||
|
||||
|
||||
func testEncodingInitialization() {
|
||||
@Test func initializeEncoding() {
|
||||
|
||||
XCTAssertEqual(String.Encoding(cfEncodings: CFStringEncodings.dosJapanese), .shiftJIS)
|
||||
XCTAssertNotEqual(String.Encoding(cfEncodings: CFStringEncodings.shiftJIS), .shiftJIS)
|
||||
XCTAssertNotEqual(String.Encoding(cfEncodings: CFStringEncodings.shiftJIS_X0213), .shiftJIS)
|
||||
#expect(String.Encoding(cfEncodings: CFStringEncodings.dosJapanese) == .shiftJIS)
|
||||
#expect(String.Encoding(cfEncodings: CFStringEncodings.shiftJIS) != .shiftJIS)
|
||||
#expect(String.Encoding(cfEncodings: CFStringEncodings.shiftJIS_X0213) != .shiftJIS)
|
||||
|
||||
XCTAssertEqual(String.Encoding(cfEncoding: CFStringEncoding(CFStringEncodings.dosJapanese.rawValue)), .shiftJIS)
|
||||
XCTAssertNotEqual(String.Encoding(cfEncoding: CFStringEncoding(CFStringEncodings.shiftJIS.rawValue)), .shiftJIS)
|
||||
XCTAssertNotEqual(String.Encoding(cfEncoding: CFStringEncoding(CFStringEncodings.shiftJIS_X0213.rawValue)), .shiftJIS)
|
||||
#expect(String.Encoding(cfEncoding: CFStringEncoding(CFStringEncodings.dosJapanese.rawValue)) == .shiftJIS)
|
||||
#expect(String.Encoding(cfEncoding: CFStringEncoding(CFStringEncodings.shiftJIS.rawValue)) != .shiftJIS)
|
||||
#expect(String.Encoding(cfEncoding: CFStringEncoding(CFStringEncodings.shiftJIS_X0213.rawValue)) != .shiftJIS)
|
||||
}
|
||||
|
||||
|
||||
/// Makes sure the behaviors around Shift-JIS.
|
||||
func testShiftJIS() {
|
||||
@Test func shiftJIS() {
|
||||
|
||||
let shiftJIS = CFStringEncoding(CFStringEncodings.shiftJIS.rawValue)
|
||||
let shiftJIS_X0213 = CFStringEncoding(CFStringEncodings.shiftJIS_X0213.rawValue)
|
||||
@ -171,68 +169,68 @@ final class EncodingDetectionTests: XCTestCase {
|
||||
|
||||
// IANA charset name conversion
|
||||
// CFStringEncoding -> IANA charset name
|
||||
XCTAssertEqual(CFStringConvertEncodingToIANACharSetName(shiftJIS) as String, "shift_jis")
|
||||
XCTAssertEqual(CFStringConvertEncodingToIANACharSetName(shiftJIS_X0213) as String, "Shift_JIS")
|
||||
#expect(CFStringConvertEncodingToIANACharSetName(shiftJIS) as String == "shift_jis")
|
||||
#expect(CFStringConvertEncodingToIANACharSetName(shiftJIS_X0213) as String == "Shift_JIS")
|
||||
|
||||
XCTAssertEqual(CFStringConvertEncodingToIANACharSetName(dosJapanese) as String, "cp932")
|
||||
#expect(CFStringConvertEncodingToIANACharSetName(dosJapanese) as String == "cp932")
|
||||
// IANA charset name -> CFStringEncoding
|
||||
XCTAssertEqual(CFStringConvertIANACharSetNameToEncoding("SHIFT_JIS" as CFString), shiftJIS)
|
||||
XCTAssertEqual(CFStringConvertIANACharSetNameToEncoding("shift_jis" as CFString), shiftJIS)
|
||||
XCTAssertEqual(CFStringConvertIANACharSetNameToEncoding("cp932" as CFString), dosJapanese)
|
||||
XCTAssertEqual(CFStringConvertIANACharSetNameToEncoding("sjis" as CFString), dosJapanese)
|
||||
XCTAssertEqual(CFStringConvertIANACharSetNameToEncoding("shiftjis" as CFString), dosJapanese)
|
||||
XCTAssertNotEqual(CFStringConvertIANACharSetNameToEncoding("shift_jis" as CFString), shiftJIS_X0213)
|
||||
#expect(CFStringConvertIANACharSetNameToEncoding("SHIFT_JIS" as CFString) == shiftJIS)
|
||||
#expect(CFStringConvertIANACharSetNameToEncoding("shift_jis" as CFString) == shiftJIS)
|
||||
#expect(CFStringConvertIANACharSetNameToEncoding("cp932" as CFString) == dosJapanese)
|
||||
#expect(CFStringConvertIANACharSetNameToEncoding("sjis" as CFString) == dosJapanese)
|
||||
#expect(CFStringConvertIANACharSetNameToEncoding("shiftjis" as CFString) == dosJapanese)
|
||||
#expect(CFStringConvertIANACharSetNameToEncoding("shift_jis" as CFString) != shiftJIS_X0213)
|
||||
|
||||
// `String.Encoding.shiftJIS` is "Japanese (Windows, DOS)."
|
||||
XCTAssertEqual(CFStringConvertNSStringEncodingToEncoding(String.Encoding.shiftJIS.rawValue), dosJapanese)
|
||||
#expect(CFStringConvertNSStringEncodingToEncoding(String.Encoding.shiftJIS.rawValue) == dosJapanese)
|
||||
}
|
||||
|
||||
|
||||
func testXattrEncoding() {
|
||||
@Test func encodeXattr() {
|
||||
|
||||
let utf8Data = Data("utf-8;134217984".utf8)
|
||||
|
||||
XCTAssertEqual(String.Encoding.utf8.xattrEncodingData, utf8Data)
|
||||
XCTAssertEqual(utf8Data.decodingXattrEncoding, .utf8)
|
||||
XCTAssertEqual(Data("utf-8".utf8).decodingXattrEncoding, .utf8)
|
||||
#expect(String.Encoding.utf8.xattrEncodingData == utf8Data)
|
||||
#expect(utf8Data.decodingXattrEncoding == .utf8)
|
||||
#expect(Data("utf-8".utf8).decodingXattrEncoding == .utf8)
|
||||
|
||||
|
||||
let eucJPData = Data("euc-jp;2336".utf8)
|
||||
|
||||
XCTAssertEqual(String.Encoding.japaneseEUC.xattrEncodingData, eucJPData)
|
||||
XCTAssertEqual(eucJPData.decodingXattrEncoding, .japaneseEUC)
|
||||
XCTAssertEqual(Data("euc-jp".utf8).decodingXattrEncoding, .japaneseEUC)
|
||||
#expect(String.Encoding.japaneseEUC.xattrEncodingData == eucJPData)
|
||||
#expect(eucJPData.decodingXattrEncoding == .japaneseEUC)
|
||||
#expect(Data("euc-jp".utf8).decodingXattrEncoding == .japaneseEUC)
|
||||
}
|
||||
|
||||
|
||||
func testYenConversion() {
|
||||
@Test func convertYen() {
|
||||
|
||||
XCTAssertTrue("¥".canBeConverted(to: .utf8))
|
||||
XCTAssertTrue("¥".canBeConverted(to: String.Encoding(cfEncodings: .shiftJIS)))
|
||||
XCTAssertFalse("¥".canBeConverted(to: .shiftJIS))
|
||||
XCTAssertFalse("¥".canBeConverted(to: .japaneseEUC)) // ? (U+003F)
|
||||
XCTAssertFalse("¥".canBeConverted(to: .ascii)) // Y (U+0059)
|
||||
#expect("¥".canBeConverted(to: .utf8))
|
||||
#expect("¥".canBeConverted(to: String.Encoding(cfEncodings: .shiftJIS)))
|
||||
#expect(!"¥".canBeConverted(to: .shiftJIS))
|
||||
#expect(!"¥".canBeConverted(to: .japaneseEUC)) // ? (U+003F)
|
||||
#expect(!"¥".canBeConverted(to: .ascii)) // Y (U+0059)
|
||||
|
||||
let string = "\\ ¥ yen"
|
||||
XCTAssertEqual(string.convertYenSign(for: .utf8), string)
|
||||
XCTAssertEqual(string.convertYenSign(for: String.Encoding(cfEncodings: .shiftJIS)), string)
|
||||
XCTAssertEqual(string.convertYenSign(for: .shiftJIS), "\\ \\ yen")
|
||||
XCTAssertEqual(string.convertYenSign(for: .japaneseEUC), "\\ \\ yen")
|
||||
XCTAssertEqual(string.convertYenSign(for: .ascii), "\\ \\ yen")
|
||||
#expect(string.convertYenSign(for: .utf8) == string)
|
||||
#expect(string.convertYenSign(for: String.Encoding(cfEncodings: .shiftJIS)) == string)
|
||||
#expect(string.convertYenSign(for: .shiftJIS) == "\\ \\ yen")
|
||||
#expect(string.convertYenSign(for: .japaneseEUC) == "\\ \\ yen")
|
||||
#expect(string.convertYenSign(for: .ascii) == "\\ \\ yen")
|
||||
}
|
||||
|
||||
|
||||
func testIANACharsetName() {
|
||||
@Test func ianaCharsetName() {
|
||||
|
||||
XCTAssertEqual(String.Encoding.utf8.ianaCharSetName, "utf-8")
|
||||
XCTAssertEqual(String.Encoding.isoLatin1.ianaCharSetName, "iso-8859-1")
|
||||
#expect(String.Encoding.utf8.ianaCharSetName == "utf-8")
|
||||
#expect(String.Encoding.isoLatin1.ianaCharSetName == "iso-8859-1")
|
||||
}
|
||||
|
||||
|
||||
func testYenEncoding() throws {
|
||||
@Test func encodeYen() throws {
|
||||
|
||||
// encodings listed in faq_about_yen_backslash.html
|
||||
let ascii = try XCTUnwrap(CFStringEncodings(rawValue: CFIndex(CFStringBuiltInEncodings.ASCII.rawValue)))
|
||||
let ascii = try #require(CFStringEncodings(rawValue: CFIndex(CFStringBuiltInEncodings.ASCII.rawValue)))
|
||||
let inHelpCFEncodings: [CFStringEncodings] = [
|
||||
.dosJapanese,
|
||||
.EUC_JP, // Japanese (EUC)
|
||||
@ -274,10 +272,10 @@ final class EncodingDetectionTests: XCTestCase {
|
||||
.filter { !"¥".canBeConverted(to: $0) }
|
||||
|
||||
for encoding in yenIncompatibleEncodings {
|
||||
XCTAssert(inHelpEncodings.contains(encoding), "\(String.localizedName(of: encoding))")
|
||||
#expect(inHelpEncodings.contains(encoding), "\(String.localizedName(of: encoding))")
|
||||
}
|
||||
for encoding in inHelpEncodings {
|
||||
XCTAssert(availableEncodings.contains(encoding), "\(String.localizedName(of: encoding))")
|
||||
#expect(availableEncodings.contains(encoding), "\(String.localizedName(of: encoding))")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -307,7 +305,7 @@ private extension EncodingDetectionTests {
|
||||
func dataForFileName(_ fileName: String) throws -> Data {
|
||||
|
||||
guard
|
||||
let fileURL = self.bundle.url(forResource: fileName, withExtension: "txt", subdirectory: "Encodings")
|
||||
let fileURL = Bundle(for: type(of: self)).url(forResource: fileName, withExtension: "txt", subdirectory: "Encodings")
|
||||
else { throw CocoaError(.fileNoSuchFile) }
|
||||
|
||||
return try Data(contentsOf: fileURL)
|
||||
|
@ -23,41 +23,53 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class FileDropItemTests: XCTestCase {
|
||||
struct FileDropItemTests {
|
||||
|
||||
func testAvailability() {
|
||||
@Test func emptyAvailability() {
|
||||
|
||||
let emptyItem = FileDropItem()
|
||||
XCTAssertTrue(emptyItem.supports(extension: "JPG", scope: "foo"))
|
||||
XCTAssertTrue(emptyItem.supports(extension: "jpg", scope: nil))
|
||||
XCTAssertTrue(emptyItem.supports(extension: nil, scope: ""))
|
||||
XCTAssertTrue(emptyItem.supports(extension: nil, scope: nil))
|
||||
let item = FileDropItem()
|
||||
#expect(item.supports(extension: "JPG", scope: "foo"))
|
||||
#expect(item.supports(extension: "jpg", scope: nil))
|
||||
#expect(item.supports(extension: nil, scope: ""))
|
||||
#expect(item.supports(extension: nil, scope: nil))
|
||||
}
|
||||
|
||||
|
||||
@Test func extensionAvailability() {
|
||||
|
||||
let extensionItem = FileDropItem(format: "", extensions: ["jpg", "JPEG"])
|
||||
XCTAssertTrue(extensionItem.supports(extension: "JPG", scope: "foo"))
|
||||
XCTAssertTrue(extensionItem.supports(extension: "JPG", scope: nil))
|
||||
XCTAssertFalse(extensionItem.supports(extension: "gif", scope: "foo"))
|
||||
XCTAssertFalse(extensionItem.supports(extension: nil, scope: "foo"))
|
||||
XCTAssertFalse(extensionItem.supports(extension: nil, scope: nil))
|
||||
let item = FileDropItem(format: "", extensions: ["jpg", "JPEG"])
|
||||
#expect(item.supports(extension: "JPG", scope: "foo"))
|
||||
#expect(item.supports(extension: "JPG", scope: nil))
|
||||
#expect(!item.supports(extension: "gif", scope: "foo"))
|
||||
#expect(!item.supports(extension: nil, scope: "foo"))
|
||||
#expect(!item.supports(extension: nil, scope: nil))
|
||||
}
|
||||
|
||||
|
||||
@Test func scopeAvailability() {
|
||||
|
||||
let scopeItem = FileDropItem(format: "", scope: "foo")
|
||||
XCTAssertTrue(scopeItem.supports(extension: "JPG", scope: "foo"))
|
||||
XCTAssertTrue(scopeItem.supports(extension: "gif", scope: "foo"))
|
||||
XCTAssertTrue(scopeItem.supports(extension: nil, scope: "foo"))
|
||||
XCTAssertFalse(scopeItem.supports(extension: nil, scope: "bar"))
|
||||
XCTAssertFalse(scopeItem.supports(extension: "JPG", scope: nil))
|
||||
XCTAssertFalse(scopeItem.supports(extension: nil, scope: nil))
|
||||
let item = FileDropItem(format: "", scope: "foo")
|
||||
#expect(item.supports(extension: "JPG", scope: "foo"))
|
||||
#expect(item.supports(extension: "gif", scope: "foo"))
|
||||
#expect(item.supports(extension: nil, scope: "foo"))
|
||||
#expect(!item.supports(extension: nil, scope: "bar"))
|
||||
#expect(!item.supports(extension: "JPG", scope: nil))
|
||||
#expect(!item.supports(extension: nil, scope: nil))
|
||||
}
|
||||
|
||||
|
||||
@Test func mixAvailability() {
|
||||
|
||||
let item = FileDropItem(format: "", extensions: ["jpg", "JPEG"], scope: "foo")
|
||||
XCTAssertTrue(item.supports(extension: "JPG", scope: "foo"))
|
||||
XCTAssertTrue(item.supports(extension: "jpeg", scope: "foo"))
|
||||
XCTAssertFalse(item.supports(extension: "gif", scope: "foo"))
|
||||
XCTAssertFalse(item.supports(extension: nil, scope: "foo"))
|
||||
XCTAssertFalse(item.supports(extension: nil, scope: "bar"))
|
||||
XCTAssertFalse(item.supports(extension: "JPG", scope: nil))
|
||||
XCTAssertFalse(item.supports(extension: nil, scope: nil))
|
||||
#expect(item.supports(extension: "JPG", scope: "foo"))
|
||||
#expect(item.supports(extension: "jpeg", scope: "foo"))
|
||||
#expect(!item.supports(extension: "gif", scope: "foo"))
|
||||
#expect(!item.supports(extension: nil, scope: "foo"))
|
||||
#expect(!item.supports(extension: nil, scope: "bar"))
|
||||
#expect(!item.supports(extension: "JPG", scope: nil))
|
||||
#expect(!item.supports(extension: nil, scope: nil))
|
||||
}
|
||||
}
|
||||
|
@ -24,34 +24,34 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class FilePermissionTests: XCTestCase {
|
||||
struct FilePermissionTests {
|
||||
|
||||
func testFilePermissions() {
|
||||
@Test func filePermissions() {
|
||||
|
||||
XCTAssertEqual(FilePermissions(mask: 0o777).mask, 0o777)
|
||||
XCTAssertEqual(FilePermissions(mask: 0o643).mask, 0o643)
|
||||
#expect(FilePermissions(mask: 0o777).mask == 0o777)
|
||||
#expect(FilePermissions(mask: 0o643).mask == 0o643)
|
||||
|
||||
XCTAssertEqual(FilePermissions(mask: 0o777).symbolic, "rwxrwxrwx")
|
||||
XCTAssertEqual(FilePermissions(mask: 0o643).symbolic, "rw-r---wx")
|
||||
#expect(FilePermissions(mask: 0o777).symbolic == "rwxrwxrwx")
|
||||
#expect(FilePermissions(mask: 0o643).symbolic == "rw-r---wx")
|
||||
}
|
||||
|
||||
|
||||
func testFormatStyle() {
|
||||
@Test func formatStyle() {
|
||||
|
||||
XCTAssertEqual(FilePermissions(mask: 0o777).formatted(.filePermissions(.full)), "777 (-rwxrwxrwx)")
|
||||
XCTAssertEqual(FilePermissions(mask: 0o643).formatted(.filePermissions(.full)), "643 (-rw-r---wx)")
|
||||
#expect(FilePermissions(mask: 0o777).formatted(.filePermissions(.full)) == "777 (-rwxrwxrwx)")
|
||||
#expect(FilePermissions(mask: 0o643).formatted(.filePermissions(.full)) == "643 (-rw-r---wx)")
|
||||
}
|
||||
|
||||
|
||||
func testCalculation() {
|
||||
@Test func calculate() {
|
||||
|
||||
var permissions = FilePermissions(mask: 0o644)
|
||||
permissions.user.insert(.execute)
|
||||
|
||||
XCTAssertTrue(permissions.user.contains(.execute))
|
||||
XCTAssertEqual(permissions.mask, 0o744)
|
||||
#expect(permissions.user.contains(.execute))
|
||||
#expect(permissions.mask == 0o744)
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2016-2023 1024jp
|
||||
// © 2016-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -24,40 +24,41 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import AppKit.NSFont
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class FontExtensionTests: XCTestCase {
|
||||
struct FontExtensionTests {
|
||||
|
||||
func testFontSize() {
|
||||
@Test func fontSize() {
|
||||
|
||||
let font = NSFont(name: "Menlo-Regular", size: 11)
|
||||
|
||||
XCTAssertEqual(font?.width(of: " "), 6.62255859375)
|
||||
#expect(font?.width(of: " ") == 6.62255859375)
|
||||
}
|
||||
|
||||
|
||||
func testFontWeight() throws {
|
||||
@Test func fontWeight() throws {
|
||||
|
||||
let regularFont = try XCTUnwrap(NSFont(name: "Menlo-Regular", size: 11))
|
||||
let boldFont = try XCTUnwrap(NSFont(name: "Menlo-Bold", size: 11))
|
||||
let regularFont = try #require(NSFont(name: "Menlo-Regular", size: 11))
|
||||
let boldFont = try #require(NSFont(name: "Menlo-Bold", size: 11))
|
||||
|
||||
XCTAssertEqual(regularFont.weight, .regular)
|
||||
XCTAssertEqual(boldFont.weight.rawValue, NSFont.Weight.bold.rawValue, accuracy: 0.00001)
|
||||
#expect(regularFont.weight == .regular)
|
||||
// #expect(boldFont.weight.rawValue == NSFont.Weight.bold.rawValue) // accuracy: 0.00001
|
||||
|
||||
// The const value is (unfortunately) not exact equal...
|
||||
XCTAssertEqual(boldFont.weight.rawValue, 0.4)
|
||||
XCTAssertNotEqual(NSFont.Weight.bold.rawValue, 0.4)
|
||||
#expect(boldFont.weight.rawValue == 0.4)
|
||||
#expect(NSFont.Weight.bold.rawValue != 0.4)
|
||||
}
|
||||
|
||||
|
||||
func testNamedFont() throws {
|
||||
@Test func namedFont() throws {
|
||||
|
||||
let menlo = try XCTUnwrap(NSFont(named: .menlo, size: 11))
|
||||
XCTAssertEqual(menlo, NSFont(name: "Menlo-Regular", size: 11))
|
||||
let menlo = try #require(NSFont(named: .menlo, size: 11))
|
||||
#expect(menlo == NSFont(name: "Menlo-Regular", size: 11))
|
||||
|
||||
let avenirNextCondensed = try XCTUnwrap(NSFont(named: .avenirNextCondensed, weight: .bold, size: 11))
|
||||
XCTAssertEqual(avenirNextCondensed, NSFont(name: "AvenirNextCondensed-Bold", size: 11))
|
||||
XCTAssertEqual(avenirNextCondensed.weight.rawValue, NSFont.Weight.bold.rawValue, accuracy: 0.00001)
|
||||
let avenirNextCondensed = try #require(NSFont(named: .avenirNextCondensed, weight: .bold, size: 11))
|
||||
#expect(avenirNextCondensed == NSFont(name: "AvenirNextCondensed-Bold", size: 11))
|
||||
// #expect(avenirNextCondensed.weight.rawValue == NSFont.Weight.bold.rawValue) // accuracy: 0.00001
|
||||
}
|
||||
}
|
||||
|
@ -23,47 +23,47 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class FormatStylesTests: XCTestCase {
|
||||
struct FormatStylesTests {
|
||||
|
||||
func testCSVFormatStyle() {
|
||||
@Test func formatCSV() throws {
|
||||
|
||||
XCTAssertEqual(["dog", "cat"].formatted(.csv), "dog, cat")
|
||||
XCTAssertEqual(["dog"].formatted(.csv), "dog")
|
||||
XCTAssertEqual(["dog", "", "dog", ""].formatted(.csv), "dog, , dog, ")
|
||||
XCTAssertEqual(["dog", "", "dog", ""].formatted(.csv(omittingEmptyItems: true)), "dog, dog")
|
||||
#expect(["dog", "cat"].formatted(.csv) == "dog, cat")
|
||||
#expect(["dog"].formatted(.csv) == "dog")
|
||||
#expect(["dog", "", "dog", ""].formatted(.csv) == "dog, , dog, ")
|
||||
#expect(["dog", "", "dog", ""].formatted(.csv(omittingEmptyItems: true)) == "dog, dog")
|
||||
|
||||
let strategy = CSVFormatStyle().parseStrategy
|
||||
XCTAssertEqual(try strategy.parse("dog, cat"), ["dog", "cat"])
|
||||
XCTAssertEqual(try strategy.parse(" a,b,c"), ["a", "b", "c"])
|
||||
XCTAssertEqual(try strategy.parse(" a, ,c"), ["a", "", "c"])
|
||||
XCTAssertEqual(try CSVFormatStyle(omittingEmptyItems: true).parseStrategy.parse(" a,,c"), ["a", "c"])
|
||||
#expect(try strategy.parse("dog, cat") == ["dog", "cat"])
|
||||
#expect(try strategy.parse(" a,b,c") == ["a", "b", "c"])
|
||||
#expect(try strategy.parse(" a, ,c") == ["a", "", "c"])
|
||||
#expect(try CSVFormatStyle(omittingEmptyItems: true).parseStrategy.parse(" a,,c") == ["a", "c"])
|
||||
}
|
||||
|
||||
|
||||
func testRangedInteger() throws {
|
||||
@Test func rangedInteger() throws {
|
||||
|
||||
let formatter = RangedIntegerFormatStyle(range: 1...(.max))
|
||||
|
||||
XCTAssertEqual(formatter.format(-3), "1")
|
||||
XCTAssertEqual(try formatter.parseStrategy.parse("0"), 1)
|
||||
XCTAssertEqual(try formatter.parseStrategy.parse("1"), 1)
|
||||
XCTAssertEqual(try formatter.parseStrategy.parse("2"), 2)
|
||||
XCTAssertEqual(try formatter.parseStrategy.parse("a"), 1)
|
||||
#expect(formatter.format(-3) == "1")
|
||||
#expect(try formatter.parseStrategy.parse("0") == 1)
|
||||
#expect(try formatter.parseStrategy.parse("1") == 1)
|
||||
#expect(try formatter.parseStrategy.parse("2") == 2)
|
||||
#expect(try formatter.parseStrategy.parse("a") == 1)
|
||||
}
|
||||
|
||||
|
||||
func testRangedIntegerWithDefault() throws {
|
||||
@Test func rangedIntegerWithDefault() throws {
|
||||
|
||||
let formatter = RangedIntegerFormatStyle(range: -1...(.max), defaultValue: 4)
|
||||
|
||||
XCTAssertEqual(formatter.format(-3), "-1")
|
||||
XCTAssertEqual(try formatter.parseStrategy.parse("-2"), -1)
|
||||
XCTAssertEqual(try formatter.parseStrategy.parse("-1"), -1)
|
||||
XCTAssertEqual(try formatter.parseStrategy.parse("0"), 0)
|
||||
XCTAssertEqual(try formatter.parseStrategy.parse("2"), 2)
|
||||
XCTAssertEqual(try formatter.parseStrategy.parse("a"), 4)
|
||||
#expect(formatter.format(-3) == "-1")
|
||||
#expect(try formatter.parseStrategy.parse("-2") == -1)
|
||||
#expect(try formatter.parseStrategy.parse("-1") == -1)
|
||||
#expect(try formatter.parseStrategy.parse("0") == 0)
|
||||
#expect(try formatter.parseStrategy.parse("2") == 2)
|
||||
#expect(try formatter.parseStrategy.parse("a") == 4)
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2016-2020 1024jp
|
||||
// © 2016-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -24,14 +24,15 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class FourCharCodeTests: XCTestCase {
|
||||
struct FourCharCodeTests {
|
||||
|
||||
func testInitializer() {
|
||||
@Test func initialize() {
|
||||
|
||||
XCTAssertEqual(FourCharCode(stringLiteral: "TEXT"), NSHFSTypeCodeFromFileType("'TEXT'"))
|
||||
XCTAssertEqual("rtfd", NSHFSTypeCodeFromFileType("'rtfd'"))
|
||||
#expect(FourCharCode(stringLiteral: "TEXT") == NSHFSTypeCodeFromFileType("'TEXT'"))
|
||||
#expect("rtfd" == NSHFSTypeCodeFromFileType("'rtfd'"))
|
||||
}
|
||||
}
|
||||
|
@ -23,114 +23,116 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class FuzzyRangeTests: XCTestCase {
|
||||
struct FuzzyRangeTests {
|
||||
|
||||
func testFuzzyCharacterRange() {
|
||||
@Test func fuzzyCharacterRange() {
|
||||
|
||||
let string = "0123456789"
|
||||
|
||||
XCTAssertEqual(string.range(in: FuzzyRange(location: 2, length: 2)), NSRange(location: 2, length: 2))
|
||||
XCTAssertEqual(string.range(in: FuzzyRange(location: -1, length: 0)), NSRange(location: 10, length: 0))
|
||||
XCTAssertEqual(string.range(in: FuzzyRange(location: -2, length: 1)), NSRange(location: 9, length: 1))
|
||||
XCTAssertEqual(string.range(in: FuzzyRange(location: 3, length: -1)), NSRange(3..<9))
|
||||
XCTAssertEqual(string.range(in: FuzzyRange(location: 3, length: -2)), NSRange(location: 3, length: "45678".utf16.count))
|
||||
#expect(string.range(in: FuzzyRange(location: 2, length: 2)) == NSRange(location: 2, length: 2))
|
||||
#expect(string.range(in: FuzzyRange(location: -1, length: 0)) == NSRange(location: 10, length: 0))
|
||||
#expect(string.range(in: FuzzyRange(location: -2, length: 1)) == NSRange(location: 9, length: 1))
|
||||
#expect(string.range(in: FuzzyRange(location: 3, length: -1)) == NSRange(3..<9))
|
||||
#expect(string.range(in: FuzzyRange(location: 3, length: -2)) == NSRange(location: 3, length: "45678".utf16.count))
|
||||
|
||||
// grapheme cluster count
|
||||
XCTAssertEqual("black 🐈⬛ cat".range(in: FuzzyRange(location: 6, length: 2)), NSRange(location: 6, length: 5))
|
||||
#expect("black 🐈⬛ cat".range(in: FuzzyRange(location: 6, length: 2)) == NSRange(location: 6, length: 5))
|
||||
}
|
||||
|
||||
|
||||
func testFuzzyLineRange() throws {
|
||||
@Test func fuzzyLineRange() throws {
|
||||
|
||||
let string = "1\r\n2\r\n3\r\n4" // 1 based
|
||||
var range: NSRange
|
||||
|
||||
range = try XCTUnwrap(string.rangeForLine(in: FuzzyRange(location: 1, length: 2)))
|
||||
XCTAssertEqual((string as NSString).substring(with: range), "1\r\n2\r\n")
|
||||
range = try #require(string.rangeForLine(in: FuzzyRange(location: 1, length: 2)))
|
||||
#expect((string as NSString).substring(with: range) == "1\r\n2\r\n")
|
||||
|
||||
range = try XCTUnwrap(string.rangeForLine(in: FuzzyRange(location: 4, length: 1)))
|
||||
XCTAssertEqual((string as NSString).substring(with: range), "4")
|
||||
range = try #require(string.rangeForLine(in: FuzzyRange(location: 4, length: 1)))
|
||||
#expect((string as NSString).substring(with: range) == "4")
|
||||
|
||||
range = try XCTUnwrap(string.rangeForLine(in: FuzzyRange(location: 3, length: 0)))
|
||||
XCTAssertEqual((string as NSString).substring(with: range), "3\r\n")
|
||||
range = try #require(string.rangeForLine(in: FuzzyRange(location: 3, length: 0)))
|
||||
#expect((string as NSString).substring(with: range) == "3\r\n")
|
||||
|
||||
range = try XCTUnwrap(string.rangeForLine(in: FuzzyRange(location: -1, length: 1)))
|
||||
XCTAssertEqual((string as NSString).substring(with: range), "4")
|
||||
range = try #require(string.rangeForLine(in: FuzzyRange(location: -1, length: 1)))
|
||||
#expect((string as NSString).substring(with: range) == "4")
|
||||
|
||||
range = try XCTUnwrap(string.rangeForLine(in: FuzzyRange(location: -2, length: 1)))
|
||||
XCTAssertEqual((string as NSString).substring(with: range), "3\r\n")
|
||||
range = try #require(string.rangeForLine(in: FuzzyRange(location: -2, length: 1)))
|
||||
#expect((string as NSString).substring(with: range) == "3\r\n")
|
||||
|
||||
range = try XCTUnwrap(string.rangeForLine(in: FuzzyRange(location: 2, length: -2)))
|
||||
XCTAssertEqual((string as NSString).substring(with: range), "2\r\n")
|
||||
range = try #require(string.rangeForLine(in: FuzzyRange(location: 2, length: -2)))
|
||||
#expect((string as NSString).substring(with: range) == "2\r\n")
|
||||
|
||||
range = try XCTUnwrap("1\n".rangeForLine(in: FuzzyRange(location: -1, length: 0)))
|
||||
XCTAssertEqual(range, NSRange(location: 2, length: 0))
|
||||
range = try #require("1\n".rangeForLine(in: FuzzyRange(location: -1, length: 0)))
|
||||
#expect(range == NSRange(location: 2, length: 0))
|
||||
|
||||
range = try XCTUnwrap(string.rangeForLine(in: FuzzyRange(location: 1, length: 2), includingLineEnding: false))
|
||||
XCTAssertEqual((string as NSString).substring(with: range), "1\r\n2")
|
||||
range = try #require(string.rangeForLine(in: FuzzyRange(location: 1, length: 2), includingLineEnding: false))
|
||||
#expect((string as NSString).substring(with: range) == "1\r\n2")
|
||||
}
|
||||
|
||||
|
||||
func testFormattingFuzzyRange() {
|
||||
@Test func formatFuzzyRange() {
|
||||
|
||||
XCTAssertEqual(FuzzyRange(location: 0, length: 0).formatted(), "0")
|
||||
XCTAssertEqual(FuzzyRange(location: 1, length: 0).formatted(), "1")
|
||||
XCTAssertEqual(FuzzyRange(location: 1, length: 1).formatted(), "1")
|
||||
XCTAssertEqual(FuzzyRange(location: 1, length: 2).formatted(), "1:2")
|
||||
XCTAssertEqual(FuzzyRange(location: -1, length: 0).formatted(), "-1")
|
||||
XCTAssertEqual(FuzzyRange(location: -1, length: -1).formatted(), "-1:-1")
|
||||
#expect(FuzzyRange(location: 0, length: 0).formatted() == "0")
|
||||
#expect(FuzzyRange(location: 1, length: 0).formatted() == "1")
|
||||
#expect(FuzzyRange(location: 1, length: 1).formatted() == "1")
|
||||
#expect(FuzzyRange(location: 1, length: 2).formatted() == "1:2")
|
||||
#expect(FuzzyRange(location: -1, length: 0).formatted() == "-1")
|
||||
#expect(FuzzyRange(location: -1, length: -1).formatted() == "-1:-1")
|
||||
}
|
||||
|
||||
|
||||
func testParsingFuzzyRange() throws {
|
||||
@Test func parseFuzzyRange() throws {
|
||||
|
||||
let parser = FuzzyRangeParseStrategy()
|
||||
|
||||
XCTAssertEqual(try parser.parse("0"), FuzzyRange(location: 0, length: 0))
|
||||
XCTAssertEqual(try parser.parse("1"), FuzzyRange(location: 1, length: 0))
|
||||
XCTAssertEqual(try parser.parse("1:2"), FuzzyRange(location: 1, length: 2))
|
||||
XCTAssertEqual(try parser.parse("-1"), FuzzyRange(location: -1, length: 0))
|
||||
XCTAssertEqual(try parser.parse("-1:-1"), FuzzyRange(location: -1, length: -1))
|
||||
XCTAssertThrowsError(try parser.parse(""))
|
||||
XCTAssertThrowsError(try parser.parse("abc"))
|
||||
XCTAssertThrowsError(try parser.parse("1:a"))
|
||||
XCTAssertThrowsError(try parser.parse("1:1:1"))
|
||||
#expect(try parser.parse("0") == FuzzyRange(location: 0, length: 0))
|
||||
#expect(try parser.parse("1") == FuzzyRange(location: 1, length: 0))
|
||||
#expect(try parser.parse("1:2") == FuzzyRange(location: 1, length: 2))
|
||||
#expect(try parser.parse("-1") == FuzzyRange(location: -1, length: 0))
|
||||
#expect(try parser.parse("-1:-1") == FuzzyRange(location: -1, length: -1))
|
||||
|
||||
#expect(throws: FuzzyRangeParseStrategy.ParseError.invalidValue) { try parser.parse("") }
|
||||
#expect(throws: FuzzyRangeParseStrategy.ParseError.invalidValue) { try parser.parse("abc") }
|
||||
#expect(throws: FuzzyRangeParseStrategy.ParseError.invalidValue) { try parser.parse("1:a") }
|
||||
#expect(throws: FuzzyRangeParseStrategy.ParseError.invalidValue) { try parser.parse("1:1:1") }
|
||||
}
|
||||
|
||||
|
||||
func testFuzzyLocation() throws {
|
||||
@Test func fuzzyLocation() throws {
|
||||
|
||||
let string = "1\r\n2\r\n3\r\n456\n567" // 1 based
|
||||
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: 0), 0)
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: 0, column: 1), 1)
|
||||
#expect(try string.fuzzyLocation(line: 0) == 0)
|
||||
#expect(try string.fuzzyLocation(line: 0, column: 1) == 1)
|
||||
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: 1), 0)
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: 2), 3)
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: 4), 9)
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: 5), 13)
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: -1), 13)
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: -2), 9)
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: -5), 0)
|
||||
XCTAssertThrowsError(try string.fuzzyLocation(line: -6))
|
||||
#expect(try string.fuzzyLocation(line: 1) == 0)
|
||||
#expect(try string.fuzzyLocation(line: 2) == 3)
|
||||
#expect(try string.fuzzyLocation(line: 4) == 9)
|
||||
#expect(try string.fuzzyLocation(line: 5) == 13)
|
||||
#expect(try string.fuzzyLocation(line: -1) == 13)
|
||||
#expect(try string.fuzzyLocation(line: -2) == 9)
|
||||
#expect(try string.fuzzyLocation(line: -5) == 0)
|
||||
#expect(throws: FuzzyLocationError.self) { try string.fuzzyLocation(line: -6) }
|
||||
|
||||
// line with a line ending
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: 4, column: 0), 9)
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: 4, column: 1), 10)
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: 4, column: 3), 12)
|
||||
XCTAssertThrowsError(try string.fuzzyLocation(line: 4, column: 4))
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: 4, column: -1), 12)
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: 4, column: -2), 11)
|
||||
#expect(try string.fuzzyLocation(line: 4, column: 0) == 9)
|
||||
#expect(try string.fuzzyLocation(line: 4, column: 1) == 10)
|
||||
#expect(try string.fuzzyLocation(line: 4, column: 3) == 12)
|
||||
#expect(throws: FuzzyLocationError.self) { try string.fuzzyLocation(line: 4, column: 4) }
|
||||
#expect(try string.fuzzyLocation(line: 4, column: -1) == 12)
|
||||
#expect(try string.fuzzyLocation(line: 4, column: -2) == 11)
|
||||
|
||||
// line without any line endings (the last line)
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: 5, column: 0), 13)
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: 5, column: 1), 14)
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: 5, column: 3), 16)
|
||||
XCTAssertThrowsError(try string.fuzzyLocation(line: 5, column: 4))
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: 5, column: -1), 16)
|
||||
XCTAssertEqual(try string.fuzzyLocation(line: 5, column: -2), 15)
|
||||
#expect(try string.fuzzyLocation(line: 5, column: 0) == 13)
|
||||
#expect(try string.fuzzyLocation(line: 5, column: 1) == 14)
|
||||
#expect(try string.fuzzyLocation(line: 5, column: 3) == 16)
|
||||
#expect(throws: FuzzyLocationError.self) { try string.fuzzyLocation(line: 5, column: 4) }
|
||||
#expect(try string.fuzzyLocation(line: 5, column: -1) == 16)
|
||||
#expect(try string.fuzzyLocation(line: 5, column: -2) == 15)
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2016-2022 1024jp
|
||||
// © 2016-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -24,37 +24,38 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import CoreGraphics
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class GeometryTests: XCTestCase {
|
||||
struct GeometryTests {
|
||||
|
||||
func testScaling() {
|
||||
@Test func scale() {
|
||||
|
||||
XCTAssertEqual(CGSize.unit.scaled(to: 0.5), CGSize(width: 0.5, height: 0.5))
|
||||
XCTAssertEqual(CGPoint(x: 2, y: 1).scaled(to: 2), CGPoint(x: 4, y: 2))
|
||||
XCTAssertEqual(CGRect(x: 2, y: 1, width: 2, height: 1).scaled(to: 2),
|
||||
CGRect(x: 4, y: 2, width: 4, height: 2))
|
||||
#expect(CGSize.unit.scaled(to: 0.5) == CGSize(width: 0.5, height: 0.5))
|
||||
#expect(CGPoint(x: 2, y: 1).scaled(to: 2) == CGPoint(x: 4, y: 2))
|
||||
#expect(CGRect(x: 2, y: 1, width: 2, height: 1).scaled(to: 2) ==
|
||||
CGRect(x: 4, y: 2, width: 4, height: 2))
|
||||
}
|
||||
|
||||
|
||||
func testRectMid() {
|
||||
@Test func rectMid() {
|
||||
|
||||
XCTAssertEqual(CGRect(x: 1, y: 2, width: 2, height: 4).mid, CGPoint(x: 2, y: 4))
|
||||
#expect(CGRect(x: 1, y: 2, width: 2, height: 4).mid == CGPoint(x: 2, y: 4))
|
||||
}
|
||||
|
||||
|
||||
func testPrefix() {
|
||||
@Test func prefix() {
|
||||
|
||||
XCTAssertEqual(-CGPoint(x: 2, y: 3), CGPoint(x: -2, y: -3))
|
||||
XCTAssertEqual(-CGSize(width: 2, height: 3), CGSize(width: -2, height: -3))
|
||||
#expect(-CGPoint(x: 2, y: 3) == CGPoint(x: -2, y: -3))
|
||||
#expect(-CGSize(width: 2, height: 3) == CGSize(width: -2, height: -3))
|
||||
}
|
||||
|
||||
|
||||
func testOffset() {
|
||||
@Test func offset() {
|
||||
|
||||
XCTAssertEqual(CGPoint(x: 2, y: 3).offsetBy(dx: 4, dy: 5), CGPoint(x: 6, y: 8))
|
||||
XCTAssertEqual(CGPoint(x: 2, y: 3).offset(by: -CGPoint(x: 2, y: 3)), .zero)
|
||||
XCTAssertEqual(CGPoint(x: 2, y: 3).offset(by: -CGSize(width: 2, height: 3)), .zero)
|
||||
#expect(CGPoint(x: 2, y: 3).offsetBy(dx: 4, dy: 5) == CGPoint(x: 6, y: 8))
|
||||
#expect(CGPoint(x: 2, y: 3).offset(by: -CGPoint(x: 2, y: 3)) == .zero)
|
||||
#expect(CGPoint(x: 2, y: 3).offset(by: -CGSize(width: 2, height: 3)) == .zero)
|
||||
}
|
||||
}
|
||||
|
@ -24,61 +24,62 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class IncompatibleCharacterTests: XCTestCase {
|
||||
struct IncompatibleCharacterTests {
|
||||
|
||||
func testIncompatibleCharacterScan() throws {
|
||||
@Test func scanIncompatibleCharacter() throws {
|
||||
|
||||
let string = "abc\\ \n ¥ \n ~"
|
||||
let incompatibles = try string.charactersIncompatible(with: .plainShiftJIS)
|
||||
|
||||
XCTAssertEqual(incompatibles.count, 2)
|
||||
#expect(incompatibles.count == 2)
|
||||
|
||||
let backslash = try XCTUnwrap(incompatibles.first)
|
||||
let backslash = try #require(incompatibles.first)
|
||||
|
||||
XCTAssertEqual(backslash.value.character, "\\")
|
||||
XCTAssertEqual(backslash.value.converted, "\")
|
||||
XCTAssertEqual(backslash.location, 3)
|
||||
#expect(backslash.value.character == "\\")
|
||||
#expect(backslash.value.converted == "\")
|
||||
#expect(backslash.location == 3)
|
||||
|
||||
let tilde = incompatibles[1]
|
||||
|
||||
XCTAssertEqual(tilde.value.character, "~")
|
||||
XCTAssertEqual(tilde.value.converted, "?")
|
||||
XCTAssertEqual(tilde.location, 11)
|
||||
#expect(tilde.value.character == "~")
|
||||
#expect(tilde.value.converted == "?")
|
||||
#expect(tilde.location == 11)
|
||||
}
|
||||
|
||||
|
||||
func testSequentialIncompatibleCharactersScan() throws {
|
||||
@Test func scanSequentialIncompatibleCharacters() throws {
|
||||
|
||||
let string = "~~"
|
||||
let incompatibles = try string.charactersIncompatible(with: .plainShiftJIS)
|
||||
|
||||
XCTAssertEqual(incompatibles.count, 2)
|
||||
#expect(incompatibles.count == 2)
|
||||
|
||||
let tilde = incompatibles[1]
|
||||
|
||||
XCTAssertEqual(tilde.value.character, "~")
|
||||
XCTAssertEqual(tilde.value.converted, "?")
|
||||
XCTAssertEqual(tilde.location, 1)
|
||||
#expect(tilde.value.character == "~")
|
||||
#expect(tilde.value.converted == "?")
|
||||
#expect(tilde.location == 1)
|
||||
}
|
||||
|
||||
|
||||
func testIncompatibleCharacterScanWithLengthShift() throws {
|
||||
@Test func scanIncompatibleCharacterWithLengthShift() throws {
|
||||
|
||||
let string = "family 👨👨👦 with 🐕"
|
||||
let incompatibles = try string.charactersIncompatible(with: .japaneseEUC)
|
||||
|
||||
XCTAssertEqual(incompatibles.count, 2)
|
||||
#expect(incompatibles.count == 2)
|
||||
|
||||
XCTAssertEqual(incompatibles[0].value.character, "👨👨👦")
|
||||
XCTAssertEqual(incompatibles[0].value.converted, "????????")
|
||||
XCTAssertEqual(incompatibles[0].location, 7)
|
||||
#expect(incompatibles[0].value.character == "👨👨👦")
|
||||
#expect(incompatibles[0].value.converted == "????????")
|
||||
#expect(incompatibles[0].location == 7)
|
||||
|
||||
XCTAssertEqual(incompatibles[1].value.character, "🐕")
|
||||
XCTAssertEqual(incompatibles[1].value.converted, "??")
|
||||
XCTAssertEqual(incompatibles[1].location, 21)
|
||||
#expect(incompatibles[1].value.character == "🐕")
|
||||
#expect(incompatibles[1].value.converted == "??")
|
||||
#expect(incompatibles[1].location == 21)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,12 +23,13 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import AppKit
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class LineEndingScannerTests: XCTestCase {
|
||||
struct LineEndingScannerTests {
|
||||
|
||||
func testScanner() {
|
||||
@Test func scan() {
|
||||
|
||||
let storage = NSTextStorage(string: "dog\ncat\r\ncow")
|
||||
let scanner = LineEndingScanner(textStorage: storage, lineEnding: .lf)
|
||||
@ -36,28 +37,28 @@ final class LineEndingScannerTests: XCTestCase {
|
||||
storage.replaceCharacters(in: NSRange(0..<3), with: "dog\u{85}cow")
|
||||
|
||||
// test line ending scan
|
||||
XCTAssertEqual(scanner.inconsistentLineEndings,
|
||||
[ValueRange(value: .nel, range: NSRange(location: 3, length: 1)),
|
||||
ValueRange(value: .crlf, range: NSRange(location: 11, length: 2))])
|
||||
#expect(scanner.inconsistentLineEndings ==
|
||||
[ValueRange(value: .nel, range: NSRange(location: 3, length: 1)),
|
||||
ValueRange(value: .crlf, range: NSRange(location: 11, length: 2))])
|
||||
}
|
||||
|
||||
|
||||
func testEmpty() {
|
||||
@Test func empty() {
|
||||
|
||||
let storage = NSTextStorage(string: "\r")
|
||||
let scanner = LineEndingScanner(textStorage: storage, lineEnding: .lf)
|
||||
|
||||
XCTAssertEqual(scanner.inconsistentLineEndings, [ValueRange(value: .cr, range: NSRange(location: 0, length: 1))])
|
||||
#expect(scanner.inconsistentLineEndings == [ValueRange(value: .cr, range: NSRange(location: 0, length: 1))])
|
||||
|
||||
// test scanRange does not expand to the out of range
|
||||
storage.replaceCharacters(in: NSRange(0..<1), with: "")
|
||||
|
||||
// test line ending scan
|
||||
XCTAssert(scanner.inconsistentLineEndings.isEmpty)
|
||||
#expect(scanner.inconsistentLineEndings.isEmpty)
|
||||
}
|
||||
|
||||
|
||||
func testCRLFEditing() {
|
||||
@Test func editCRLF() {
|
||||
|
||||
let storage = NSTextStorage(string: "dog\ncat\r\ncow")
|
||||
let scanner = LineEndingScanner(textStorage: storage, lineEnding: .lf)
|
||||
@ -68,64 +69,63 @@ final class LineEndingScannerTests: XCTestCase {
|
||||
storage.replaceCharacters(in: NSRange(9..<10), with: "")
|
||||
|
||||
// test line ending scan
|
||||
XCTAssertEqual(scanner.inconsistentLineEndings,
|
||||
[ValueRange(value: .crlf, range: NSRange(location: 3, length: 2)),
|
||||
ValueRange(value: .cr, range: NSRange(location: 8, length: 1))])
|
||||
#expect(scanner.inconsistentLineEndings ==
|
||||
[ValueRange(value: .crlf, range: NSRange(location: 3, length: 2)),
|
||||
ValueRange(value: .cr, range: NSRange(location: 8, length: 1))])
|
||||
}
|
||||
|
||||
|
||||
func testDetection() {
|
||||
@Test func detect() {
|
||||
|
||||
let storage = NSTextStorage()
|
||||
let scanner = LineEndingScanner(textStorage: storage, lineEnding: .lf)
|
||||
|
||||
XCTAssertNil(scanner.majorLineEnding)
|
||||
#expect(scanner.majorLineEnding == nil)
|
||||
|
||||
storage.string = "a"
|
||||
XCTAssertNil(scanner.majorLineEnding)
|
||||
#expect(scanner.majorLineEnding == nil)
|
||||
|
||||
storage.string = "\n"
|
||||
XCTAssertEqual(scanner.majorLineEnding, .lf)
|
||||
#expect(scanner.majorLineEnding == .lf)
|
||||
|
||||
storage.string = "\r"
|
||||
XCTAssertEqual(scanner.majorLineEnding, .cr)
|
||||
#expect(scanner.majorLineEnding == .cr)
|
||||
|
||||
storage.string = "\r\n"
|
||||
XCTAssertEqual(scanner.majorLineEnding, .crlf)
|
||||
#expect(scanner.majorLineEnding == .crlf)
|
||||
|
||||
storage.string = "\u{85}"
|
||||
XCTAssertEqual(scanner.majorLineEnding, .nel)
|
||||
#expect(scanner.majorLineEnding == .nel)
|
||||
|
||||
storage.string = "abc\u{2029}def"
|
||||
XCTAssertEqual(scanner.majorLineEnding, .paragraphSeparator)
|
||||
#expect(scanner.majorLineEnding == .paragraphSeparator)
|
||||
|
||||
storage.string = "\rfoo\r\nbar\nbuz\u{2029}moin\r\n"
|
||||
XCTAssertEqual(scanner.majorLineEnding, .crlf) // most used new line must be detected
|
||||
#expect(scanner.majorLineEnding == .crlf) // most used new line must be detected
|
||||
}
|
||||
|
||||
|
||||
func testLineNumberCalculation() {
|
||||
@Test func calculateLineNumber() {
|
||||
|
||||
let storage = NSTextStorage(string: "dog \n\n cat \n cow \n")
|
||||
let scanner = LineEndingScanner(textStorage: storage, lineEnding: .lf)
|
||||
|
||||
XCTAssertEqual(scanner.lineNumber(at: 0), 1)
|
||||
XCTAssertEqual(scanner.lineNumber(at: 1), 1)
|
||||
XCTAssertEqual(scanner.lineNumber(at: 4), 1)
|
||||
XCTAssertEqual(scanner.lineNumber(at: 5), 2)
|
||||
XCTAssertEqual(scanner.lineNumber(at: 6), 3)
|
||||
XCTAssertEqual(scanner.lineNumber(at: 11), 3)
|
||||
XCTAssertEqual(scanner.lineNumber(at: 12), 4)
|
||||
XCTAssertEqual(scanner.lineNumber(at: 17), 4)
|
||||
XCTAssertEqual(scanner.lineNumber(at: 18), 5)
|
||||
#expect(scanner.lineNumber(at: 0) == 1)
|
||||
#expect(scanner.lineNumber(at: 1) == 1)
|
||||
#expect(scanner.lineNumber(at: 4) == 1)
|
||||
#expect(scanner.lineNumber(at: 5) == 2)
|
||||
#expect(scanner.lineNumber(at: 6) == 3)
|
||||
#expect(scanner.lineNumber(at: 11) == 3)
|
||||
#expect(scanner.lineNumber(at: 12) == 4)
|
||||
#expect(scanner.lineNumber(at: 17) == 4)
|
||||
#expect(scanner.lineNumber(at: 18) == 5)
|
||||
|
||||
for _ in 0..<20 {
|
||||
storage.string = String(" 🐶 \n 🐱 \n 🐮 \n".shuffled())
|
||||
|
||||
for index in (0..<storage.length).shuffled() {
|
||||
XCTAssertEqual(scanner.lineNumber(at: index),
|
||||
storage.string.lineNumber(at: index),
|
||||
"At \(index) with string \"\(storage.string)\"")
|
||||
#expect(scanner.lineNumber(at: index) == storage.string.lineNumber(at: index),
|
||||
"At \(index) with string \"\(storage.string)\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,28 +24,29 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class LineEndingTests: XCTestCase {
|
||||
struct LineEndingTests {
|
||||
|
||||
func testLineEnding() {
|
||||
@Test func lineEnding() {
|
||||
|
||||
XCTAssertEqual(LineEnding.lf.rawValue, "\n")
|
||||
XCTAssertEqual(LineEnding.crlf.rawValue, "\r\n")
|
||||
XCTAssertEqual(LineEnding.paragraphSeparator.rawValue, "\u{2029}")
|
||||
#expect(LineEnding.lf.rawValue == "\n")
|
||||
#expect(LineEnding.crlf.rawValue == "\r\n")
|
||||
#expect(LineEnding.paragraphSeparator.rawValue == "\u{2029}")
|
||||
}
|
||||
|
||||
|
||||
func testName() {
|
||||
@Test func name() {
|
||||
|
||||
XCTAssertEqual(LineEnding.lf.label, "LF")
|
||||
XCTAssertEqual(LineEnding.crlf.label, "CRLF")
|
||||
XCTAssertEqual(LineEnding.paragraphSeparator.label, "PS")
|
||||
#expect(LineEnding.lf.label == "LF")
|
||||
#expect(LineEnding.crlf.label == "CRLF")
|
||||
#expect(LineEnding.paragraphSeparator.label == "PS")
|
||||
}
|
||||
|
||||
|
||||
func testLineEndingRanges() {
|
||||
@Test func lineEndingRanges() {
|
||||
|
||||
let string = "\rfoo\r\nbar \n \nb \n\r uz\u{2029}moin\r\n"
|
||||
let expected: [ValueRange<LineEnding>] = [
|
||||
@ -59,16 +60,16 @@ final class LineEndingTests: XCTestCase {
|
||||
.init(value: .crlf, location: 25),
|
||||
]
|
||||
|
||||
XCTAssert("".lineEndingRanges().isEmpty)
|
||||
XCTAssert("abc".lineEndingRanges().isEmpty)
|
||||
XCTAssertEqual(string.lineEndingRanges(), expected)
|
||||
#expect("".lineEndingRanges().isEmpty)
|
||||
#expect("abc".lineEndingRanges().isEmpty)
|
||||
#expect(string.lineEndingRanges() == expected)
|
||||
}
|
||||
|
||||
|
||||
func testReplacement() {
|
||||
@Test func replace() {
|
||||
|
||||
XCTAssertEqual("foo\r\nbar\n".replacingLineEndings(with: .cr), "foo\rbar\r")
|
||||
XCTAssertEqual("foo\u{c}bar\n".replacingLineEndings(with: .cr), "foo\u{c}bar\r")
|
||||
#expect("foo\r\nbar\n".replacingLineEndings(with: .cr) == "foo\rbar\r")
|
||||
#expect("foo\u{c}bar\n".replacingLineEndings(with: .cr) == "foo\u{c}bar\r")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2020-2023 1024jp
|
||||
// © 2020-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -23,29 +23,30 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class LineRangeCacheableTests: XCTestCase {
|
||||
struct LineRangeCacheableTests {
|
||||
|
||||
private let repeatCount = 20
|
||||
|
||||
|
||||
func testLineNumberCalculation() {
|
||||
@Test func calculateLineNumber() {
|
||||
|
||||
let lineString = LineString("dog \n\n cat \n cow \n")
|
||||
XCTAssertEqual(lineString.lineNumber(at: 0), 1)
|
||||
XCTAssertEqual(lineString.lineNumber(at: 1), 1)
|
||||
XCTAssertEqual(lineString.lineNumber(at: 4), 1)
|
||||
XCTAssertEqual(lineString.lineNumber(at: 5), 2)
|
||||
XCTAssertEqual(lineString.lineNumber(at: 6), 3)
|
||||
XCTAssertEqual(lineString.lineNumber(at: 11), 3)
|
||||
XCTAssertEqual(lineString.lineNumber(at: 12), 4)
|
||||
XCTAssertEqual(lineString.lineNumber(at: 17), 4)
|
||||
XCTAssertEqual(lineString.lineNumber(at: 18), 5)
|
||||
#expect(lineString.lineNumber(at: 0) == 1)
|
||||
#expect(lineString.lineNumber(at: 1) == 1)
|
||||
#expect(lineString.lineNumber(at: 4) == 1)
|
||||
#expect(lineString.lineNumber(at: 5) == 2)
|
||||
#expect(lineString.lineNumber(at: 6) == 3)
|
||||
#expect(lineString.lineNumber(at: 11) == 3)
|
||||
#expect(lineString.lineNumber(at: 12) == 4)
|
||||
#expect(lineString.lineNumber(at: 17) == 4)
|
||||
#expect(lineString.lineNumber(at: 18) == 5)
|
||||
|
||||
let lineString2 = LineString("dog \n\n cat \n cow ")
|
||||
XCTAssertEqual(lineString2.lineNumber(at: 17), 4)
|
||||
#expect(lineString2.lineNumber(at: 17) == 4)
|
||||
|
||||
for _ in 0..<self.repeatCount {
|
||||
let string = String(" 🐶 \n 🐱 \n 🐮 \n".shuffled())
|
||||
@ -53,27 +54,28 @@ final class LineRangeCacheableTests: XCTestCase {
|
||||
|
||||
for index in (0...string.length).shuffled() {
|
||||
let result = (string as NSString).lineNumber(at: index)
|
||||
XCTAssertEqual(lineString.lineNumber(at: index), result, "At \(index) with string \"\(string)\"")
|
||||
#expect(lineString.lineNumber(at: index) == result,
|
||||
"At \(index) with string \"\(string)\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testIndexToLineRangeCalculation() {
|
||||
@Test func calculateIndexToLineRange() {
|
||||
|
||||
let lineString = LineString("dog \n\n cat \n cow \n")
|
||||
XCTAssertEqual(lineString.lineRange(at: 0), NSRange(0..<5))
|
||||
XCTAssertEqual(lineString.lineRange(at: 1), NSRange(0..<5))
|
||||
XCTAssertEqual(lineString.lineRange(at: 4), NSRange(0..<5))
|
||||
XCTAssertEqual(lineString.lineRange(at: 5), NSRange(5..<6))
|
||||
XCTAssertEqual(lineString.lineRange(at: 6), NSRange(6..<12))
|
||||
XCTAssertEqual(lineString.lineRange(at: 11), NSRange(6..<12))
|
||||
XCTAssertEqual(lineString.lineRange(at: 12), NSRange(12..<18))
|
||||
XCTAssertEqual(lineString.lineRange(at: 17), NSRange(12..<18))
|
||||
XCTAssertEqual(lineString.lineRange(at: 18), NSRange(18..<18))
|
||||
#expect(lineString.lineRange(at: 0) == NSRange(0..<5))
|
||||
#expect(lineString.lineRange(at: 1) == NSRange(0..<5))
|
||||
#expect(lineString.lineRange(at: 4) == NSRange(0..<5))
|
||||
#expect(lineString.lineRange(at: 5) == NSRange(5..<6))
|
||||
#expect(lineString.lineRange(at: 6) == NSRange(6..<12))
|
||||
#expect(lineString.lineRange(at: 11) == NSRange(6..<12))
|
||||
#expect(lineString.lineRange(at: 12) == NSRange(12..<18))
|
||||
#expect(lineString.lineRange(at: 17) == NSRange(12..<18))
|
||||
#expect(lineString.lineRange(at: 18) == NSRange(18..<18))
|
||||
|
||||
let lineString2 = LineString("dog \n\n cat \n cow ")
|
||||
XCTAssertEqual(lineString2.lineRange(at: 17), NSRange(12..<17))
|
||||
#expect(lineString2.lineRange(at: 17) == NSRange(12..<17))
|
||||
|
||||
for _ in 0..<self.repeatCount {
|
||||
let string = String(" 🐶 \n 🐱 \n 🐮 \n".shuffled())
|
||||
@ -81,66 +83,69 @@ final class LineRangeCacheableTests: XCTestCase {
|
||||
|
||||
for index in (0...string.length).shuffled() {
|
||||
let result = (string as NSString).lineRange(at: index)
|
||||
XCTAssertEqual(lineString.lineRange(at: index), result, "At \(index) with string \"\(string)\"")
|
||||
XCTAssertEqual(lineString.lineStartIndex(at: index), result.lowerBound, "At \(index) with string \"\(string)\"")
|
||||
#expect(lineString.lineRange(at: index) == result,
|
||||
"At \(index) with string \"\(string)\"")
|
||||
#expect(lineString.lineStartIndex(at: index) == result.lowerBound,
|
||||
"At \(index) with string \"\(string)\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testLineContentRange() {
|
||||
@Test func lineContentRange() {
|
||||
|
||||
let lineString = LineString("dog \n\n cat \n cow")
|
||||
XCTAssertEqual(lineString.lineContentRange(for: NSRange(0..<3)), NSRange(0..<4))
|
||||
XCTAssertEqual(lineString.lineContentRange(for: NSRange(4..<6)), NSRange(0..<6))
|
||||
XCTAssertEqual(lineString.lineContentRange(for: NSRange(5..<6)), NSRange(5..<6))
|
||||
XCTAssertEqual(lineString.lineContentRange(for: NSRange(7..<13)), NSRange(6..<16))
|
||||
#expect(lineString.lineContentRange(for: NSRange(0..<3)) == NSRange(0..<4))
|
||||
#expect(lineString.lineContentRange(for: NSRange(4..<6)) == NSRange(0..<6))
|
||||
#expect(lineString.lineContentRange(for: NSRange(5..<6)) == NSRange(5..<6))
|
||||
#expect(lineString.lineContentRange(for: NSRange(7..<13)) == NSRange(6..<16))
|
||||
}
|
||||
|
||||
|
||||
func testRangeToLineRangeCalculation() throws {
|
||||
@Test func calculateRangeToLineRange() throws {
|
||||
|
||||
let lineString = LineString("dog \n\n cat \n cow \n")
|
||||
XCTAssertEqual(lineString.lineRange(for: NSRange(0..<3)), NSRange(0..<5))
|
||||
XCTAssertEqual(lineString.lineRange(for: NSRange(0..<5)), NSRange(0..<5))
|
||||
XCTAssertEqual(lineString.lineRange(for: NSRange(0..<6)), NSRange(0..<6))
|
||||
XCTAssertEqual(lineString.lineRange(for: NSRange(5..<5)), NSRange(5..<6))
|
||||
XCTAssertEqual(lineString.lineRange(for: NSRange(5..<6)), NSRange(5..<6))
|
||||
XCTAssertEqual(lineString.lineRange(for: NSRange(5..<7)), NSRange(5..<12))
|
||||
XCTAssertEqual(lineString.lineRange(for: NSRange(6..<6)), NSRange(6..<12))
|
||||
XCTAssertEqual(lineString.lineRange(for: NSRange(6..<7)), NSRange(6..<12))
|
||||
XCTAssertEqual(lineString.lineRange(for: NSRange(6..<17)), NSRange(6..<18))
|
||||
XCTAssertEqual(lineString.lineRange(for: NSRange(17..<17)), NSRange(12..<18))
|
||||
XCTAssertEqual(lineString.lineRange(for: NSRange(17..<18)), NSRange(12..<18))
|
||||
XCTAssertEqual(lineString.lineRange(for: NSRange(18..<18)), NSRange(18..<18))
|
||||
#expect(lineString.lineRange(for: NSRange(0..<3)) == NSRange(0..<5))
|
||||
#expect(lineString.lineRange(for: NSRange(0..<5)) == NSRange(0..<5))
|
||||
#expect(lineString.lineRange(for: NSRange(0..<6)) == NSRange(0..<6))
|
||||
#expect(lineString.lineRange(for: NSRange(5..<5)) == NSRange(5..<6))
|
||||
#expect(lineString.lineRange(for: NSRange(5..<6)) == NSRange(5..<6))
|
||||
#expect(lineString.lineRange(for: NSRange(5..<7)) == NSRange(5..<12))
|
||||
#expect(lineString.lineRange(for: NSRange(6..<6)) == NSRange(6..<12))
|
||||
#expect(lineString.lineRange(for: NSRange(6..<7)) == NSRange(6..<12))
|
||||
#expect(lineString.lineRange(for: NSRange(6..<17)) == NSRange(6..<18))
|
||||
#expect(lineString.lineRange(for: NSRange(17..<17)) == NSRange(12..<18))
|
||||
#expect(lineString.lineRange(for: NSRange(17..<18)) == NSRange(12..<18))
|
||||
#expect(lineString.lineRange(for: NSRange(18..<18)) == NSRange(18..<18))
|
||||
|
||||
let lineString2 = LineString("dog \n\n cat \n cow ")
|
||||
XCTAssertEqual(lineString2.lineRange(for: NSRange(15..<17)), NSRange(12..<17))
|
||||
XCTAssertEqual(lineString2.lineRange(for: NSRange(17..<17)), NSRange(12..<17))
|
||||
#expect(lineString2.lineRange(for: NSRange(15..<17)) == NSRange(12..<17))
|
||||
#expect(lineString2.lineRange(for: NSRange(17..<17)) == NSRange(12..<17))
|
||||
|
||||
for _ in 0..<self.repeatCount {
|
||||
let string = String(" 🐶 \n 🐱 \n 🐮 \n".shuffled())
|
||||
let lineString = LineString(string)
|
||||
|
||||
for index in (0...string.length).shuffled() {
|
||||
let endIndex = try XCTUnwrap((index...string.length).randomElement())
|
||||
let endIndex = try #require((index...string.length).randomElement())
|
||||
let range = NSRange(index..<endIndex)
|
||||
let result = (string as NSString).lineRange(for: range)
|
||||
|
||||
XCTAssertEqual(lineString.lineRange(for: range), result, "At \(index) with string \"\(string)\"")
|
||||
#expect(lineString.lineRange(for: range) == result,
|
||||
"At \(index) with string \"\(string)\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testStringInvalidation() {
|
||||
@Test func invalidateString() {
|
||||
|
||||
let lineString = LineString("\n🐶")
|
||||
let lineNumber = lineString.lineNumber(at: 1)
|
||||
let lineRange = lineString.lineRange(at: 1)
|
||||
lineString.invalidateLineRanges(in: NSRange(1..<2), changeInLength: 0)
|
||||
XCTAssertEqual(lineString.lineNumber(at: 1), lineNumber) // 2
|
||||
XCTAssertEqual(lineString.lineRange(at: 1), lineRange) // NSRange(1..<3)
|
||||
#expect(lineString.lineNumber(at: 1) == lineNumber) // 2
|
||||
#expect(lineString.lineRange(at: 1) == lineRange) // NSRange(1..<3)
|
||||
|
||||
for _ in 0..<self.repeatCount {
|
||||
let lineString = LineString(String(" 🐶 \n 🐱 \n 🐮 \n".shuffled()))
|
||||
@ -152,58 +157,61 @@ final class LineRangeCacheableTests: XCTestCase {
|
||||
|
||||
lineString.invalidateLineRanges(in: range, changeInLength: 0)
|
||||
|
||||
XCTAssertEqual(lineString.lineNumber(at: index), lineNumber, "At \(index) with string \"\(lineString.string)\"")
|
||||
XCTAssertEqual(lineString.lineRange(at: index), lineRange, "At \(index) with string \"\(lineString.string)\"")
|
||||
XCTAssertEqual(lineString.lineStartIndex(at: index), lineRange.lowerBound, "At \(index) with string \"\(lineString.string)\"")
|
||||
#expect(lineString.lineNumber(at: index) == lineNumber,
|
||||
"At \(index) with string \"\(lineString.string)\"")
|
||||
#expect(lineString.lineRange(at: index) == lineRange,
|
||||
"At \(index) with string \"\(lineString.string)\"")
|
||||
#expect(lineString.lineStartIndex(at: index) == lineRange.lowerBound,
|
||||
"At \(index) with string \"\(lineString.string)\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testStringRemoval() {
|
||||
@Test func removeString() {
|
||||
|
||||
let lineString = LineString("dog \n\n\n cat \n ")
|
||||
_ = lineString.lineNumber(at: lineString.string.length)
|
||||
|
||||
lineString.replaceCharacters(in: NSRange(1..<3), with: "") // "og"
|
||||
XCTAssertEqual(lineString.string, "d \n\n\n cat \n ")
|
||||
XCTAssertEqual(lineString.lineNumber(at: 1), 1)
|
||||
XCTAssertEqual(lineString.lineRange(at: 1), NSRange(0..<3)) // "d \n"
|
||||
XCTAssertEqual(lineString.lineNumber(at: 3), 2)
|
||||
XCTAssertEqual(lineString.lineRange(at: 3), NSRange(3..<4)) // "\n"
|
||||
XCTAssertEqual(lineString.lineRange(at: 4), NSRange(4..<5)) // "\n"
|
||||
XCTAssertEqual(lineString.lineRange(at: 5), NSRange(5..<11)) // " cat \n"
|
||||
#expect(lineString.string == "d \n\n\n cat \n ")
|
||||
#expect(lineString.lineNumber(at: 1) == 1)
|
||||
#expect(lineString.lineRange(at: 1) == NSRange(0..<3)) // "d \n"
|
||||
#expect(lineString.lineNumber(at: 3) == 2)
|
||||
#expect(lineString.lineRange(at: 3) == NSRange(3..<4)) // "\n"
|
||||
#expect(lineString.lineRange(at: 4) == NSRange(4..<5)) // "\n"
|
||||
#expect(lineString.lineRange(at: 5) == NSRange(5..<11)) // " cat \n"
|
||||
|
||||
lineString.replaceCharacters(in: NSRange(1..<2), with: "") // 1st " "
|
||||
XCTAssertEqual(lineString.string, "d\n\n\n cat \n ")
|
||||
XCTAssertEqual(lineString.lineNumber(at: 1), 1)
|
||||
XCTAssertEqual(lineString.lineRange(at: 1), NSRange(0..<2)) // "d\n"
|
||||
XCTAssertEqual(lineString.lineRange(at: 2), NSRange(2..<3)) // "\n"
|
||||
XCTAssertEqual(lineString.lineRange(at: 3), NSRange(3..<4)) // "\n"
|
||||
XCTAssertEqual(lineString.lineRange(at: 4), NSRange(4..<10)) // " cat \n"
|
||||
#expect(lineString.string == "d\n\n\n cat \n ")
|
||||
#expect(lineString.lineNumber(at: 1) == 1)
|
||||
#expect(lineString.lineRange(at: 1) == NSRange(0..<2)) // "d\n"
|
||||
#expect(lineString.lineRange(at: 2) == NSRange(2..<3)) // "\n"
|
||||
#expect(lineString.lineRange(at: 3) == NSRange(3..<4)) // "\n"
|
||||
#expect(lineString.lineRange(at: 4) == NSRange(4..<10)) // " cat \n"
|
||||
|
||||
lineString.replaceCharacters(in: NSRange(2..<4), with: "") // "\n\n"
|
||||
XCTAssertEqual(lineString.string, "d\n cat \n ")
|
||||
XCTAssertEqual(lineString.lineNumber(at: 1), 1)
|
||||
XCTAssertEqual(lineString.lineRange(at: 1), NSRange(0..<2)) // "d\n"
|
||||
XCTAssertEqual(lineString.lineRange(at: 2), NSRange(2..<8)) // " cat \n"
|
||||
#expect(lineString.string == "d\n cat \n ")
|
||||
#expect(lineString.lineNumber(at: 1) == 1)
|
||||
#expect(lineString.lineRange(at: 1) == NSRange(0..<2)) // "d\n"
|
||||
#expect(lineString.lineRange(at: 2) == NSRange(2..<8)) // " cat \n"
|
||||
}
|
||||
|
||||
|
||||
func testStringModification() {
|
||||
@Test func modifyString() {
|
||||
|
||||
let lineString = LineString("\n🐶")
|
||||
_ = lineString.lineNumber(at: 1)
|
||||
lineString.replaceCharacters(in: NSRange(1..<3), with: "a\nb")
|
||||
lineString.invalidateLineRanges(in: NSRange(1..<3), changeInLength: 1)
|
||||
XCTAssertEqual(lineString.lineNumber(at: 1), 2)
|
||||
XCTAssertEqual(lineString.lineRange(at: 1), NSRange(1..<3)) // "a\n"
|
||||
#expect(lineString.lineNumber(at: 1) == 2)
|
||||
#expect(lineString.lineRange(at: 1) == NSRange(1..<3)) // "a\n"
|
||||
|
||||
for _ in 0..<self.repeatCount {
|
||||
let string = String(" dog \n cat \n cow \n".shuffled())
|
||||
let lineString = LineString(string)
|
||||
|
||||
XCTAssertEqual(lineString.lineNumber(at: string.length), 4)
|
||||
#expect(lineString.lineNumber(at: string.length) == 4)
|
||||
|
||||
let location = Int.random(in: 0..<(string.length - 1))
|
||||
let length = Int.random(in: 0..<(string.length - location))
|
||||
@ -213,30 +221,29 @@ final class LineRangeCacheableTests: XCTestCase {
|
||||
lineString.replaceCharacters(in: range, with: replacement)
|
||||
|
||||
for index in (0...lineString.string.length).shuffled() {
|
||||
XCTAssertEqual(lineString.lineNumber(at: index), lineString.string.lineNumber(at: index),
|
||||
"at \(index) with string \"\(lineString.string)\"")
|
||||
XCTAssertEqual(lineString.lineRange(at: index), lineString.string.lineRange(at: index),
|
||||
"at \(index) with string \"\(lineString.string)\"")
|
||||
XCTAssertEqual(lineString.lineStartIndex(at: index), lineString.string.lineStartIndex(at: index),
|
||||
"at \(index) with string \"\(lineString.string)\"")
|
||||
#expect(lineString.lineNumber(at: index) == lineString.string.lineNumber(at: index),
|
||||
"at \(index) with string \"\(lineString.string)\"")
|
||||
#expect(lineString.lineRange(at: index) == lineString.string.lineRange(at: index),
|
||||
"at \(index) with string \"\(lineString.string)\"")
|
||||
#expect(lineString.lineStartIndex(at: index) == lineString.string.lineStartIndex(at: index),
|
||||
"at \(index) with string \"\(lineString.string)\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testEdgeModification() {
|
||||
@Test func modifyEdge() {
|
||||
|
||||
let lineString = LineString("\n \n")
|
||||
|
||||
XCTAssertEqual(lineString.lineNumber(at: 4), 3)
|
||||
#expect(lineString.lineNumber(at: 4) == 3)
|
||||
|
||||
lineString.replaceCharacters(in: NSRange(0..<0), with: " ")
|
||||
|
||||
let index = 4
|
||||
XCTAssertEqual(lineString.string, " \n \n")
|
||||
XCTAssertEqual(lineString.lineNumber(at: index), 2)
|
||||
XCTAssertEqual(lineString.lineRange(at: index), NSRange(location: 3, length: 3))
|
||||
XCTAssertEqual(lineString.lineStartIndex(at: index), 3)
|
||||
#expect(lineString.string == " \n \n")
|
||||
#expect(lineString.lineNumber(at: 4) == 2)
|
||||
#expect(lineString.lineRange(at: 4) == NSRange(location: 3, length: 3))
|
||||
#expect(lineString.lineStartIndex(at: 4) == 3)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,10 +24,11 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class LineSortTests: XCTestCase {
|
||||
struct LineSortTests {
|
||||
|
||||
private let lines = """
|
||||
dog, 🐕, 2, イヌ
|
||||
@ -36,7 +37,7 @@ final class LineSortTests: XCTestCase {
|
||||
"""
|
||||
|
||||
|
||||
func testCSVSort() {
|
||||
@Test func csvSort() {
|
||||
|
||||
var pattern = CSVSortPattern()
|
||||
pattern.column = 3
|
||||
@ -47,14 +48,14 @@ final class LineSortTests: XCTestCase {
|
||||
cow, 🐄, 3, ウシ
|
||||
"""
|
||||
|
||||
XCTAssertEqual(pattern.sort(self.lines), result)
|
||||
XCTAssertEqual(pattern.sort(""), "")
|
||||
XCTAssertNoThrow(try pattern.validate())
|
||||
XCTAssertNil(pattern.range(for: "dog, 🐕, , イヌ"))
|
||||
#expect(pattern.sort(self.lines) == result)
|
||||
#expect(pattern.sort("").isEmpty)
|
||||
#expect(throws: Never.self) { try pattern.validate() }
|
||||
#expect(pattern.range(for: "dog, 🐕, , イヌ") == nil)
|
||||
}
|
||||
|
||||
|
||||
func testRegexSort() throws {
|
||||
@Test func regexSort() throws {
|
||||
|
||||
var pattern = RegularExpressionSortPattern()
|
||||
pattern.searchPattern = ", ([0-9]),"
|
||||
@ -65,24 +66,24 @@ final class LineSortTests: XCTestCase {
|
||||
cow, 🐄, 3, ウシ
|
||||
"""
|
||||
|
||||
XCTAssertEqual(pattern.sort(self.lines), result)
|
||||
#expect(pattern.sort(self.lines) == result)
|
||||
|
||||
pattern.usesCaptureGroup = true
|
||||
pattern.group = 1
|
||||
XCTAssertEqual(pattern.sort(self.lines), result)
|
||||
XCTAssertEqual(pattern.sort(""), "")
|
||||
XCTAssertNoThrow(try pattern.validate())
|
||||
#expect(pattern.sort(self.lines) == result)
|
||||
#expect(pattern.sort("").isEmpty)
|
||||
#expect(throws: Never.self) { try pattern.validate() }
|
||||
|
||||
pattern.searchPattern = "\\"
|
||||
XCTAssertThrowsError(try pattern.validate())
|
||||
#expect(throws: SortPatternError.invalidRegularExpressionPattern) { try pattern.validate() }
|
||||
|
||||
pattern.searchPattern = "(a)(b)c"
|
||||
try pattern.validate()
|
||||
XCTAssertEqual(pattern.numberOfCaptureGroups, 2)
|
||||
#expect(pattern.numberOfCaptureGroups == 2)
|
||||
}
|
||||
|
||||
|
||||
func testFuzzySort() {
|
||||
@Test func fuzzySort() {
|
||||
|
||||
var pattern = CSVSortPattern()
|
||||
pattern.column = 4
|
||||
@ -96,13 +97,13 @@ final class LineSortTests: XCTestCase {
|
||||
cat, 🐈, 1, ねこ
|
||||
"""
|
||||
|
||||
XCTAssertEqual(pattern.sort(self.lines, options: options), result)
|
||||
XCTAssertEqual(pattern.sort(""), "")
|
||||
XCTAssertNoThrow(try pattern.validate())
|
||||
#expect(pattern.sort(self.lines, options: options) == result)
|
||||
#expect(pattern.sort("").isEmpty)
|
||||
#expect(throws: Never.self) { try pattern.validate() }
|
||||
}
|
||||
|
||||
|
||||
func testNumericSorts() {
|
||||
@Test func numericSort() {
|
||||
|
||||
let pattern = EntireLineSortPattern()
|
||||
let numbers = """
|
||||
@ -114,71 +115,71 @@ final class LineSortTests: XCTestCase {
|
||||
var options = SortOptions()
|
||||
|
||||
options.numeric = false
|
||||
XCTAssertEqual(pattern.sort(numbers, options: options), "1\n12\n3")
|
||||
#expect(pattern.sort(numbers, options: options) == "1\n12\n3")
|
||||
|
||||
options.numeric = true
|
||||
XCTAssertEqual(pattern.sort(numbers, options: options), "1\n3\n12")
|
||||
#expect(pattern.sort(numbers, options: options) == "1\n3\n12")
|
||||
|
||||
options.descending = true
|
||||
XCTAssertEqual(pattern.sort(numbers, options: options), "12\n3\n1")
|
||||
#expect(pattern.sort(numbers, options: options) == "12\n3\n1")
|
||||
|
||||
options.descending = false
|
||||
options.keepsFirstLine = true
|
||||
XCTAssertEqual(pattern.sort(numbers, options: options), "3\n1\n12")
|
||||
#expect(pattern.sort(numbers, options: options) == "3\n1\n12")
|
||||
}
|
||||
|
||||
|
||||
func testTargetRange() throws {
|
||||
@Test func targetRange() throws {
|
||||
|
||||
let string = "dog"
|
||||
XCTAssertEqual(EntireLineSortPattern().range(for: string), string.startIndex..<string.endIndex)
|
||||
XCTAssertEqual(CSVSortPattern().range(for: string), string.startIndex..<string.endIndex)
|
||||
XCTAssertNil(RegularExpressionSortPattern().range(for: string))
|
||||
#expect(EntireLineSortPattern().range(for: string) == string.startIndex..<string.endIndex)
|
||||
#expect(CSVSortPattern().range(for: string) == string.startIndex..<string.endIndex)
|
||||
#expect(RegularExpressionSortPattern().range(for: string) == nil)
|
||||
|
||||
XCTAssertEqual(CSVSortPattern().range(for: ""), Range(NSRange(0..<0), in: ""))
|
||||
#expect(CSVSortPattern().range(for: "") == Range(NSRange(0..<0), in: ""))
|
||||
|
||||
let csvString = " dog , dog cow "
|
||||
var pattern = CSVSortPattern()
|
||||
pattern.column = 2
|
||||
XCTAssertEqual(pattern.range(for: csvString), Range(NSRange(8..<15), in: csvString))
|
||||
#expect(pattern.range(for: csvString) == Range(NSRange(8..<15), in: csvString))
|
||||
|
||||
let tsvString = "a\tb"
|
||||
pattern.column = 1
|
||||
let range = try XCTUnwrap(pattern.range(for: tsvString))
|
||||
XCTAssertEqual(pattern.sortKey(for: tsvString), tsvString)
|
||||
XCTAssertEqual(NSRange(range, in: tsvString), NSRange(0..<3))
|
||||
let range = try #require(pattern.range(for: tsvString))
|
||||
#expect(pattern.sortKey(for: tsvString) == tsvString)
|
||||
#expect(NSRange(range, in: tsvString) == NSRange(0..<3))
|
||||
}
|
||||
|
||||
|
||||
func testNumberParse() throws {
|
||||
@Test func parseNumber() throws {
|
||||
|
||||
var options = SortOptions()
|
||||
|
||||
options.locale = .init(identifier: "en")
|
||||
XCTAssertTrue(options.isLocalized)
|
||||
XCTAssertTrue(options.numeric)
|
||||
XCTAssertEqual(options.parse("0"), 0)
|
||||
XCTAssertEqual(options.parse("10 000"), 10000)
|
||||
XCTAssertEqual(options.parse("-1000.1 m/s"), -1000.1)
|
||||
XCTAssertEqual(options.parse("-1000,1 m/s"), -1000)
|
||||
XCTAssertEqual(options.parse("+1,000"), 1000)
|
||||
XCTAssertNil(options.parse("dog 10"))
|
||||
#expect(options.isLocalized)
|
||||
#expect(options.numeric)
|
||||
#expect(options.parse("0") == 0)
|
||||
#expect(options.parse("10 000") == 10000)
|
||||
#expect(options.parse("-1000.1 m/s") == -1000.1)
|
||||
#expect(options.parse("-1000,1 m/s") == -1000)
|
||||
#expect(options.parse("+1,000") == 1000)
|
||||
#expect(options.parse("dog 10") == nil)
|
||||
|
||||
options.locale = .init(identifier: "de")
|
||||
XCTAssertTrue(options.numeric)
|
||||
XCTAssertEqual(options.parse("0"), 0)
|
||||
XCTAssertEqual(options.parse("10 000"), 10000)
|
||||
XCTAssertEqual(options.parse("-1000.1 m/s"), -1000)
|
||||
XCTAssertEqual(options.parse("-1000,1 m/s"), -1000.1)
|
||||
XCTAssertEqual(options.parse("+1,000"), 1)
|
||||
XCTAssertNil(options.parse("dog 10"))
|
||||
#expect(options.numeric)
|
||||
#expect(options.parse("0") == 0)
|
||||
#expect(options.parse("10 000") == 10000)
|
||||
#expect(options.parse("-1000.1 m/s") == -1000)
|
||||
#expect(options.parse("-1000,1 m/s") == -1000.1)
|
||||
#expect(options.parse("+1,000") == 1)
|
||||
#expect(options.parse("dog 10") == nil)
|
||||
|
||||
options.numeric = false
|
||||
XCTAssertNil(options.parse("0"))
|
||||
XCTAssertNil(options.parse("10 000"))
|
||||
XCTAssertNil(options.parse("-1000.1 m/s"))
|
||||
XCTAssertNil(options.parse("-1000,1 m/s"))
|
||||
XCTAssertNil(options.parse("+1,000"))
|
||||
XCTAssertNil(options.parse("dog 10"))
|
||||
#expect(options.parse("0") == nil)
|
||||
#expect(options.parse("10 000") == nil)
|
||||
#expect(options.parse("-1000.1 m/s") == nil)
|
||||
#expect(options.parse("-1000,1 m/s") == nil)
|
||||
#expect(options.parse("+1,000") == nil)
|
||||
#expect(options.parse("dog 10") == nil)
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2020-2023 1024jp
|
||||
// © 2020-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -23,69 +23,70 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class NSAttributedStringTests: XCTestCase {
|
||||
struct NSAttributedStringTests {
|
||||
|
||||
func testAddition() throws {
|
||||
@Test func add() throws {
|
||||
|
||||
let foo = NSMutableAttributedString(string: "foo", attributes: [.toolTip: "moof"])
|
||||
let bar = NSAttributedString(string: "bar", attributes: [:])
|
||||
let fooBar = foo + bar
|
||||
|
||||
XCTAssertFalse(fooBar is NSMutableAttributedString)
|
||||
XCTAssertEqual(fooBar.string, "foobar")
|
||||
XCTAssertEqual(fooBar.attribute(.toolTip, at: 1, effectiveRange: nil) as? String, "moof")
|
||||
XCTAssertNil(fooBar.attribute(.toolTip, at: 3, effectiveRange: nil))
|
||||
#expect(!(fooBar is NSMutableAttributedString))
|
||||
#expect(fooBar.string == "foobar")
|
||||
#expect(fooBar.attribute(.toolTip, at: 1, effectiveRange: nil) as? String == "moof")
|
||||
#expect(fooBar.attribute(.toolTip, at: 3, effectiveRange: nil) == nil)
|
||||
}
|
||||
|
||||
|
||||
func testAdditionEqual() throws {
|
||||
@Test func addEqual() throws {
|
||||
|
||||
var fooBar = NSAttributedString(string: "foo", attributes: [.toolTip: "moof"])
|
||||
fooBar += NSAttributedString(string: "bar", attributes: [:])
|
||||
|
||||
XCTAssertFalse(fooBar is NSMutableAttributedString)
|
||||
XCTAssertEqual(fooBar.string, "foobar")
|
||||
XCTAssertEqual(fooBar.attribute(.toolTip, at: 1, effectiveRange: nil) as? String, "moof")
|
||||
XCTAssertNil(fooBar.attribute(.toolTip, at: 3, effectiveRange: nil))
|
||||
#expect(!(fooBar is NSMutableAttributedString))
|
||||
#expect(fooBar.string == "foobar")
|
||||
#expect(fooBar.attribute(.toolTip, at: 1, effectiveRange: nil) as? String == "moof")
|
||||
#expect(fooBar.attribute(.toolTip, at: 3, effectiveRange: nil) == nil)
|
||||
}
|
||||
|
||||
|
||||
func testTruncation() throws {
|
||||
@Test func truncate() throws {
|
||||
|
||||
let string1 = NSMutableAttributedString(string: "0123456")
|
||||
string1.truncateHead(until: 5, offset: 2)
|
||||
XCTAssertEqual(string1.string, "…3456")
|
||||
#expect(string1.string == "…3456")
|
||||
|
||||
let string2 = NSMutableAttributedString(string: "0123456")
|
||||
string2.truncateHead(until: 2, offset: 3)
|
||||
XCTAssertEqual(string2.string, "0123456")
|
||||
#expect(string2.string == "0123456")
|
||||
|
||||
let string3 = NSMutableAttributedString(string: "🐱🐶🐮")
|
||||
string3.truncateHead(until: 4, offset: 1)
|
||||
XCTAssertEqual(string3.string, "…🐶🐮")
|
||||
#expect(string3.string == "…🐶🐮")
|
||||
|
||||
let string4 = NSMutableAttributedString(string: "🐈⬛🐕🐄")
|
||||
string4.truncateHead(until: 4, offset: 1)
|
||||
XCTAssertEqual(string4.string, "🐈⬛🐕🐄")
|
||||
#expect(string4.string == "🐈⬛🐕🐄")
|
||||
|
||||
let string5 = NSMutableAttributedString(string: "🐈⬛🐕🐄")
|
||||
string5.truncateHead(until: 5, offset: 1)
|
||||
XCTAssertEqual(string5.string, "🐈⬛🐕🐄")
|
||||
#expect(string5.string == "🐈⬛🐕🐄")
|
||||
|
||||
let string6 = NSMutableAttributedString(string: "🐈⬛ab")
|
||||
string6.truncateHead(until: 5, offset: 1)
|
||||
XCTAssertEqual(string6.string, "…ab")
|
||||
#expect(string6.string == "…ab")
|
||||
|
||||
let string7 = NSMutableAttributedString(string: "🐈⬛🐕🐄")
|
||||
string7.truncateHead(until: 6, offset: 1)
|
||||
XCTAssertEqual(string7.string, "…🐕🐄")
|
||||
#expect(string7.string == "…🐕🐄")
|
||||
}
|
||||
|
||||
|
||||
func testJoin() {
|
||||
@Test func join() {
|
||||
|
||||
let attrs: [NSAttributedString] = [
|
||||
NSMutableAttributedString(string: "foo", attributes: [.toolTip: "moof"]),
|
||||
@ -95,26 +96,26 @@ final class NSAttributedStringTests: XCTestCase {
|
||||
let space = NSAttributedString(string: " ", attributes: [.toolTip: "space"])
|
||||
|
||||
let joined = attrs.joined()
|
||||
XCTAssertFalse(joined is NSMutableAttributedString)
|
||||
XCTAssertEqual(joined.string, "foobarbuz")
|
||||
XCTAssertEqual(joined.attribute(.toolTip, at: 1, effectiveRange: nil) as? String, "moof")
|
||||
XCTAssertNil(joined.attribute(.toolTip, at: 3, effectiveRange: nil))
|
||||
#expect(!(joined is NSMutableAttributedString))
|
||||
#expect(joined.string == "foobarbuz")
|
||||
#expect(joined.attribute(.toolTip, at: 1, effectiveRange: nil) as? String == "moof")
|
||||
#expect(joined.attribute(.toolTip, at: 3, effectiveRange: nil) == nil)
|
||||
|
||||
let spaceJoined = attrs.joined(separator: space)
|
||||
XCTAssertFalse(spaceJoined is NSMutableAttributedString)
|
||||
XCTAssertEqual(spaceJoined.string, "foo bar buz")
|
||||
XCTAssertEqual(spaceJoined.attribute(.toolTip, at: 0, effectiveRange: nil) as? String, "moof")
|
||||
XCTAssertEqual(spaceJoined.attribute(.toolTip, at: 3, effectiveRange: nil) as? String, "space")
|
||||
XCTAssertNil(spaceJoined.attribute(.toolTip, at: 4, effectiveRange: nil))
|
||||
#expect(!(spaceJoined is NSMutableAttributedString))
|
||||
#expect(spaceJoined.string == "foo bar buz")
|
||||
#expect(spaceJoined.attribute(.toolTip, at: 0, effectiveRange: nil) as? String == "moof")
|
||||
#expect(spaceJoined.attribute(.toolTip, at: 3, effectiveRange: nil) as? String == "space")
|
||||
#expect(spaceJoined.attribute(.toolTip, at: 4, effectiveRange: nil) == nil)
|
||||
|
||||
let empty: [NSAttributedString] = []
|
||||
let emptyJoined = empty.joined(separator: space)
|
||||
XCTAssertFalse(emptyJoined is NSMutableAttributedString)
|
||||
XCTAssertEqual(emptyJoined.string, "")
|
||||
#expect(!(emptyJoined is NSMutableAttributedString))
|
||||
#expect(emptyJoined.string.isEmpty)
|
||||
|
||||
let single: [NSAttributedString] = [NSMutableAttributedString(string: "foo", attributes: [.toolTip: "moof"])]
|
||||
let singleJoined = single.joined(separator: space)
|
||||
XCTAssertFalse(singleJoined is NSMutableAttributedString)
|
||||
XCTAssertEqual(singleJoined.string, "foo")
|
||||
#expect(!(singleJoined is NSMutableAttributedString))
|
||||
#expect(singleJoined.string == "foo")
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2019-2023 1024jp
|
||||
// © 2019-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -24,107 +24,94 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import AppKit
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class NSLayoutManagerTests: XCTestCase {
|
||||
struct NSLayoutManagerTests {
|
||||
|
||||
func testTemporaryAttributeExistence() {
|
||||
@Test func checkTemporaryAttribute() {
|
||||
|
||||
let layoutManager = NSLayoutManager()
|
||||
let textStorage = NSTextStorage(string: "cat dog cow")
|
||||
textStorage.addLayoutManager(layoutManager)
|
||||
|
||||
XCTAssertFalse(layoutManager.hasTemporaryAttribute(.foregroundColor))
|
||||
XCTAssertFalse(layoutManager.hasTemporaryAttribute(.foregroundColor, in: NSRange(..<0)))
|
||||
#expect(!layoutManager.hasTemporaryAttribute(.foregroundColor))
|
||||
#expect(!layoutManager.hasTemporaryAttribute(.foregroundColor, in: NSRange(..<0)))
|
||||
|
||||
layoutManager.addTemporaryAttribute(.foregroundColor, value: NSColor.green, forCharacterRange: NSRange(4..<7))
|
||||
layoutManager.addTemporaryAttribute(.backgroundColor, value: NSColor.white, forCharacterRange: NSRange(6..<8))
|
||||
XCTAssertTrue(layoutManager.hasTemporaryAttribute(.foregroundColor))
|
||||
XCTAssertFalse(layoutManager.hasTemporaryAttribute(.foregroundColor, in: NSRange(..<4)))
|
||||
XCTAssertTrue(layoutManager.hasTemporaryAttribute(.foregroundColor, in: NSRange(3..<6)))
|
||||
XCTAssertTrue(layoutManager.hasTemporaryAttribute(.foregroundColor, in: NSRange(6..<8)))
|
||||
XCTAssertFalse(layoutManager.hasTemporaryAttribute(.foregroundColor, in: NSRange(7..<7)))
|
||||
XCTAssertFalse(layoutManager.hasTemporaryAttribute(.foregroundColor, in: NSRange(7..<textStorage.length)))
|
||||
#expect(layoutManager.hasTemporaryAttribute(.foregroundColor))
|
||||
#expect(!layoutManager.hasTemporaryAttribute(.foregroundColor, in: NSRange(..<4)))
|
||||
#expect(layoutManager.hasTemporaryAttribute(.foregroundColor, in: NSRange(3..<6)))
|
||||
#expect(layoutManager.hasTemporaryAttribute(.foregroundColor, in: NSRange(6..<8)))
|
||||
#expect(!layoutManager.hasTemporaryAttribute(.foregroundColor, in: NSRange(7..<7)))
|
||||
#expect(!layoutManager.hasTemporaryAttribute(.foregroundColor, in: NSRange(7..<textStorage.length)))
|
||||
}
|
||||
|
||||
|
||||
func testLeftCharacterIndex() {
|
||||
@Test func characterIndex() {
|
||||
|
||||
let layoutManager = NSLayoutManager()
|
||||
layoutManager.addTextContainer(NSTextContainer())
|
||||
let textStorage = NSTextStorage(string: "dog\r\n 🐕")
|
||||
textStorage.addLayoutManager(layoutManager)
|
||||
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 0, baseWritingDirection: .leftToRight), 0)
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 1, baseWritingDirection: .leftToRight), 0)
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 2, baseWritingDirection: .leftToRight), 1)
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 3, baseWritingDirection: .leftToRight), 2)
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 4, baseWritingDirection: .leftToRight), 2)
|
||||
// left characters
|
||||
#expect(layoutManager.leftCharacterIndex(of: 0, baseWritingDirection: .leftToRight) == 0)
|
||||
#expect(layoutManager.leftCharacterIndex(of: 1, baseWritingDirection: .leftToRight) == 0)
|
||||
#expect(layoutManager.leftCharacterIndex(of: 2, baseWritingDirection: .leftToRight) == 1)
|
||||
#expect(layoutManager.leftCharacterIndex(of: 3, baseWritingDirection: .leftToRight) == 2)
|
||||
#expect(layoutManager.leftCharacterIndex(of: 4, baseWritingDirection: .leftToRight) == 2)
|
||||
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 5, baseWritingDirection: .leftToRight), 3)
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 6, baseWritingDirection: .leftToRight), 5)
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 7, baseWritingDirection: .leftToRight), 5)
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 8, baseWritingDirection: .leftToRight), 6)
|
||||
#expect(layoutManager.leftCharacterIndex(of: 5, baseWritingDirection: .leftToRight) == 3)
|
||||
#expect(layoutManager.leftCharacterIndex(of: 6, baseWritingDirection: .leftToRight) == 5)
|
||||
#expect(layoutManager.leftCharacterIndex(of: 7, baseWritingDirection: .leftToRight) == 5)
|
||||
#expect(layoutManager.leftCharacterIndex(of: 8, baseWritingDirection: .leftToRight) == 6)
|
||||
|
||||
// right characters
|
||||
#expect(layoutManager.rightCharacterIndex(of: 0, baseWritingDirection: .leftToRight) == 1)
|
||||
#expect(layoutManager.rightCharacterIndex(of: 1, baseWritingDirection: .leftToRight) == 2)
|
||||
#expect(layoutManager.rightCharacterIndex(of: 2, baseWritingDirection: .leftToRight) == 3)
|
||||
#expect(layoutManager.rightCharacterIndex(of: 3, baseWritingDirection: .leftToRight) == 5)
|
||||
#expect(layoutManager.rightCharacterIndex(of: 4, baseWritingDirection: .leftToRight) == 5)
|
||||
|
||||
#expect(layoutManager.rightCharacterIndex(of: 5, baseWritingDirection: .leftToRight) == 6)
|
||||
#expect(layoutManager.rightCharacterIndex(of: 6, baseWritingDirection: .leftToRight) == 8)
|
||||
#expect(layoutManager.rightCharacterIndex(of: 7, baseWritingDirection: .leftToRight) == 8)
|
||||
#expect(layoutManager.rightCharacterIndex(of: 8, baseWritingDirection: .leftToRight) == 8)
|
||||
}
|
||||
|
||||
|
||||
func testRightCharacterIndex() {
|
||||
|
||||
let layoutManager = NSLayoutManager()
|
||||
layoutManager.addTextContainer(NSTextContainer())
|
||||
let textStorage = NSTextStorage(string: "dog\r\n 🐕")
|
||||
textStorage.addLayoutManager(layoutManager)
|
||||
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 0, baseWritingDirection: .leftToRight), 1)
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 1, baseWritingDirection: .leftToRight), 2)
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 2, baseWritingDirection: .leftToRight), 3)
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 3, baseWritingDirection: .leftToRight), 5)
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 4, baseWritingDirection: .leftToRight), 5)
|
||||
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 5, baseWritingDirection: .leftToRight), 6)
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 6, baseWritingDirection: .leftToRight), 8)
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 7, baseWritingDirection: .leftToRight), 8)
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 8, baseWritingDirection: .leftToRight), 8)
|
||||
}
|
||||
|
||||
|
||||
func testBidiLeftCharacterIndex() {
|
||||
@Test func bidiCharacterIndex() {
|
||||
|
||||
let layoutManager = NSLayoutManager()
|
||||
layoutManager.addTextContainer(NSTextContainer())
|
||||
let textStorage = NSTextStorage(string: "كلب\r\n 🐕")
|
||||
textStorage.addLayoutManager(layoutManager)
|
||||
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 0, baseWritingDirection: .leftToRight), 1)
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 1, baseWritingDirection: .leftToRight), 2)
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 2, baseWritingDirection: .leftToRight), 3)
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 3, baseWritingDirection: .leftToRight), 0)
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 4, baseWritingDirection: .leftToRight), 1)
|
||||
// left characters
|
||||
#expect(layoutManager.leftCharacterIndex(of: 0, baseWritingDirection: .leftToRight) == 1)
|
||||
#expect(layoutManager.leftCharacterIndex(of: 1, baseWritingDirection: .leftToRight) == 2)
|
||||
#expect(layoutManager.leftCharacterIndex(of: 2, baseWritingDirection: .leftToRight) == 3)
|
||||
#expect(layoutManager.leftCharacterIndex(of: 3, baseWritingDirection: .leftToRight) == 0)
|
||||
#expect(layoutManager.leftCharacterIndex(of: 4, baseWritingDirection: .leftToRight) == 1)
|
||||
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 5, baseWritingDirection: .leftToRight), 3)
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 6, baseWritingDirection: .leftToRight), 5)
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 7, baseWritingDirection: .leftToRight), 5)
|
||||
XCTAssertEqual(layoutManager.leftCharacterIndex(of: 8, baseWritingDirection: .leftToRight), 6)
|
||||
}
|
||||
|
||||
|
||||
func testBidiRightCharacterIndex() {
|
||||
#expect(layoutManager.leftCharacterIndex(of: 5, baseWritingDirection: .leftToRight) == 3)
|
||||
#expect(layoutManager.leftCharacterIndex(of: 6, baseWritingDirection: .leftToRight) == 5)
|
||||
#expect(layoutManager.leftCharacterIndex(of: 7, baseWritingDirection: .leftToRight) == 5)
|
||||
#expect(layoutManager.leftCharacterIndex(of: 8, baseWritingDirection: .leftToRight) == 6)
|
||||
|
||||
// right characters
|
||||
#expect(layoutManager.rightCharacterIndex(of: 0, baseWritingDirection: .leftToRight) == 5)
|
||||
#expect(layoutManager.rightCharacterIndex(of: 1, baseWritingDirection: .leftToRight) == 0)
|
||||
#expect(layoutManager.rightCharacterIndex(of: 2, baseWritingDirection: .leftToRight) == 1)
|
||||
#expect(layoutManager.rightCharacterIndex(of: 3, baseWritingDirection: .leftToRight) == 2)
|
||||
#expect(layoutManager.rightCharacterIndex(of: 4, baseWritingDirection: .leftToRight) == 5)
|
||||
|
||||
let layoutManager = NSLayoutManager()
|
||||
layoutManager.addTextContainer(NSTextContainer())
|
||||
let textStorage = NSTextStorage(string: "كلب\r\n 🐕")
|
||||
textStorage.addLayoutManager(layoutManager)
|
||||
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 0, baseWritingDirection: .leftToRight), 5)
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 1, baseWritingDirection: .leftToRight), 0)
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 2, baseWritingDirection: .leftToRight), 1)
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 3, baseWritingDirection: .leftToRight), 2)
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 4, baseWritingDirection: .leftToRight), 5)
|
||||
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 5, baseWritingDirection: .leftToRight), 6)
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 6, baseWritingDirection: .leftToRight), 8)
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 7, baseWritingDirection: .leftToRight), 8)
|
||||
XCTAssertEqual(layoutManager.rightCharacterIndex(of: 8, baseWritingDirection: .leftToRight), 8)
|
||||
#expect(layoutManager.rightCharacterIndex(of: 5, baseWritingDirection: .leftToRight) == 6)
|
||||
#expect(layoutManager.rightCharacterIndex(of: 6, baseWritingDirection: .leftToRight) == 8)
|
||||
#expect(layoutManager.rightCharacterIndex(of: 7, baseWritingDirection: .leftToRight) == 8)
|
||||
#expect(layoutManager.rightCharacterIndex(of: 8, baseWritingDirection: .leftToRight) == 8)
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2023 1024jp
|
||||
// © 2023-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -23,65 +23,66 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class NSRangeTests: XCTestCase {
|
||||
struct NSRangeTests {
|
||||
|
||||
func testBoundaryTouch() {
|
||||
@Test func touchBoundary() {
|
||||
|
||||
XCTAssert(NSRange(location: 2, length: 2).touches(NSRange(location: 4, length: 2)))
|
||||
XCTAssert(NSRange(location: 2, length: 2).touches(NSRange(location: 0, length: 2)))
|
||||
#expect(NSRange(location: 2, length: 2).touches(NSRange(location: 4, length: 2)))
|
||||
#expect(NSRange(location: 2, length: 2).touches(NSRange(location: 0, length: 2)))
|
||||
|
||||
XCTAssert(NSRange(location: 2, length: 0).touches(NSRange(location: 2, length: 2)))
|
||||
XCTAssert(NSRange(location: 2, length: 0).touches(NSRange(location: 0, length: 2)))
|
||||
XCTAssert(NSRange(location: 2, length: 2).touches(NSRange(location: 2, length: 0)))
|
||||
XCTAssert(NSRange(location: 2, length: 2).touches(NSRange(location: 4, length: 0)))
|
||||
#expect(NSRange(location: 2, length: 0).touches(NSRange(location: 2, length: 2)))
|
||||
#expect(NSRange(location: 2, length: 0).touches(NSRange(location: 0, length: 2)))
|
||||
#expect(NSRange(location: 2, length: 2).touches(NSRange(location: 2, length: 0)))
|
||||
#expect(NSRange(location: 2, length: 2).touches(NSRange(location: 4, length: 0)))
|
||||
|
||||
XCTAssert(NSRange(location: 2, length: 2).touches(2))
|
||||
XCTAssert(NSRange(location: 2, length: 2).touches(4))
|
||||
#expect(NSRange(location: 2, length: 2).touches(2))
|
||||
#expect(NSRange(location: 2, length: 2).touches(4))
|
||||
}
|
||||
|
||||
|
||||
func testNotFound() {
|
||||
@Test func notFound() {
|
||||
|
||||
XCTAssert(NSRange.notFound.isNotFound)
|
||||
XCTAssert(NSRange.notFound.isEmpty)
|
||||
XCTAssert(NSRange(location: NSNotFound, length: 1).isNotFound)
|
||||
XCTAssertFalse(NSRange(location: 1, length: 1).isNotFound)
|
||||
#expect(NSRange.notFound.isNotFound)
|
||||
#expect(NSRange.notFound.isEmpty)
|
||||
#expect(NSRange(location: NSNotFound, length: 1).isNotFound)
|
||||
#expect(!NSRange(location: 1, length: 1).isNotFound)
|
||||
}
|
||||
|
||||
|
||||
func testRangeInsertion() {
|
||||
@Test func insertRange() {
|
||||
|
||||
XCTAssertEqual(NSRange(0..<0).inserted(items: []), NSRange(0..<0))
|
||||
XCTAssertEqual(NSRange(0..<0).inserted(items: [.init(string: "", location: 0, forward: true)]), NSRange(0..<0))
|
||||
#expect(NSRange(0..<0).inserted(items: []) == NSRange(0..<0))
|
||||
#expect(NSRange(0..<0).inserted(items: [.init(string: "", location: 0, forward: true)]) == NSRange(0..<0))
|
||||
|
||||
XCTAssertEqual(NSRange(0..<0).inserted(items: [.init(string: "abc", location: 0, forward: true)]), NSRange(3..<3))
|
||||
XCTAssertEqual(NSRange(0..<0).inserted(items: [.init(string: "abc", location: 0, forward: false)]), NSRange(0..<0))
|
||||
XCTAssertEqual(NSRange(1..<1).inserted(items: [.init(string: "abc", location: 0, forward: false)]), NSRange(4..<4))
|
||||
XCTAssertEqual(NSRange(0..<5).inserted(items: [.init(string: "abc", location: 2, forward: true)]), NSRange(0..<8))
|
||||
XCTAssertEqual(NSRange(0..<5).inserted(items: [.init(string: "abc", location: 6, forward: true)]), NSRange(0..<5))
|
||||
#expect(NSRange(0..<0).inserted(items: [.init(string: "abc", location: 0, forward: true)]) == NSRange(3..<3))
|
||||
#expect(NSRange(0..<0).inserted(items: [.init(string: "abc", location: 0, forward: false)]) == NSRange(0..<0))
|
||||
#expect(NSRange(1..<1).inserted(items: [.init(string: "abc", location: 0, forward: false)]) == NSRange(4..<4))
|
||||
#expect(NSRange(0..<5).inserted(items: [.init(string: "abc", location: 2, forward: true)]) == NSRange(0..<8))
|
||||
#expect(NSRange(0..<5).inserted(items: [.init(string: "abc", location: 6, forward: true)]) == NSRange(0..<5))
|
||||
|
||||
XCTAssertEqual(NSRange(2..<2).inserted(items: [.init(string: "abc", location: 2, forward: true),
|
||||
.init(string: "abc", location: 2, forward: false)]), NSRange(5..<5))
|
||||
XCTAssertEqual(NSRange(2..<3).inserted(items: [.init(string: "abc", location: 2, forward: true),
|
||||
.init(string: "abc", location: 2, forward: false)]), NSRange(2..<6))
|
||||
XCTAssertEqual(NSRange(2..<3).inserted(items: [.init(string: "abc", location: 3, forward: true),
|
||||
.init(string: "abc", location: 3, forward: false)]), NSRange(2..<6))
|
||||
#expect(NSRange(2..<2).inserted(items: [.init(string: "abc", location: 2, forward: true),
|
||||
.init(string: "abc", location: 2, forward: false)]) == NSRange(5..<5))
|
||||
#expect(NSRange(2..<3).inserted(items: [.init(string: "abc", location: 2, forward: true),
|
||||
.init(string: "abc", location: 2, forward: false)]) == NSRange(2..<6))
|
||||
#expect(NSRange(2..<3).inserted(items: [.init(string: "abc", location: 3, forward: true),
|
||||
.init(string: "abc", location: 3, forward: false)]) == NSRange(2..<6))
|
||||
}
|
||||
|
||||
|
||||
func testRangeRemoval() {
|
||||
@Test func removeRange() {
|
||||
|
||||
XCTAssertEqual(NSRange(0..<0).removed(ranges: []), NSRange(0..<0))
|
||||
XCTAssertEqual(NSRange(0..<0).removed(ranges: [NSRange(0..<0)]), NSRange(0..<0))
|
||||
#expect(NSRange(0..<0).removed(ranges: []) == NSRange(0..<0))
|
||||
#expect(NSRange(0..<0).removed(ranges: [NSRange(0..<0)]) == NSRange(0..<0))
|
||||
|
||||
XCTAssertEqual(NSRange(0..<10).removed(ranges: [NSRange(2..<4)]), NSRange(0..<8))
|
||||
XCTAssertEqual(NSRange(1..<10).removed(ranges: [NSRange(0..<2)]), NSRange(0..<8))
|
||||
XCTAssertEqual(NSRange(1..<10).removed(ranges: [NSRange(11..<20)]), NSRange(1..<10))
|
||||
#expect(NSRange(0..<10).removed(ranges: [NSRange(2..<4)]) == NSRange(0..<8))
|
||||
#expect(NSRange(1..<10).removed(ranges: [NSRange(0..<2)]) == NSRange(0..<8))
|
||||
#expect(NSRange(1..<10).removed(ranges: [NSRange(11..<20)]) == NSRange(1..<10))
|
||||
|
||||
XCTAssertEqual(NSRange(1..<10).removed(ranges: [NSRange(2..<4), NSRange(3..<5)]), NSRange(1..<7))
|
||||
XCTAssertEqual(NSRange(1..<10).removed(ranges: [NSRange(0..<2), NSRange(3..<5), NSRange(9..<20)]), NSRange(0..<5))
|
||||
#expect(NSRange(1..<10).removed(ranges: [NSRange(2..<4), NSRange(3..<5)]) == NSRange(1..<7))
|
||||
#expect(NSRange(1..<10).removed(ranges: [NSRange(0..<2), NSRange(3..<5), NSRange(9..<20)]) == NSRange(0..<5))
|
||||
}
|
||||
}
|
||||
|
@ -23,10 +23,11 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class OutlineTests: XCTestCase {
|
||||
struct OutlineTests {
|
||||
|
||||
private let items: [OutlineItem] = [
|
||||
OutlineItem(title: "dog", range: NSRange(location: 10, length: 5)), // 0
|
||||
@ -42,49 +43,49 @@ final class OutlineTests: XCTestCase {
|
||||
|
||||
|
||||
|
||||
func testIndex() throws {
|
||||
@Test func index() throws {
|
||||
|
||||
XCTAssertNil(self.emptyItems.item(at: 10))
|
||||
#expect(self.emptyItems.item(at: 10) == nil)
|
||||
|
||||
XCTAssertNil(self.items.item(at: 9))
|
||||
XCTAssertEqual(self.items.item(at: 10), self.items[0])
|
||||
XCTAssertEqual(self.items.item(at: 18), self.items[0])
|
||||
XCTAssertEqual(self.items.item(at: 20), self.items[0])
|
||||
XCTAssertEqual(self.items.item(at: 40), self.items[3])
|
||||
XCTAssertEqual(self.items.item(at: 50), self.items[3])
|
||||
XCTAssertEqual(self.items.item(at: 59), self.items[3])
|
||||
XCTAssertEqual(self.items.item(at: 60), self.items[5])
|
||||
#expect(self.items.item(at: 9) == nil)
|
||||
#expect(self.items.item(at: 10) == self.items[0])
|
||||
#expect(self.items.item(at: 18) == self.items[0])
|
||||
#expect(self.items.item(at: 20) == self.items[0])
|
||||
#expect(self.items.item(at: 40) == self.items[3])
|
||||
#expect(self.items.item(at: 50) == self.items[3])
|
||||
#expect(self.items.item(at: 59) == self.items[3])
|
||||
#expect(self.items.item(at: 60) == self.items[5])
|
||||
}
|
||||
|
||||
|
||||
func testPreviousItem() throws {
|
||||
@Test func previousItem() throws {
|
||||
|
||||
XCTAssertNil(self.emptyItems.previousItem(for: NSRange(10..<20)))
|
||||
#expect(self.emptyItems.previousItem(for: NSRange(10..<20)) == nil)
|
||||
|
||||
XCTAssertNil(self.items.previousItem(for: NSRange(10..<20)))
|
||||
XCTAssertNil(self.items.previousItem(for: NSRange(19..<19)))
|
||||
XCTAssertEqual(self.items.previousItem(for: NSRange(59..<70)), items[0])
|
||||
XCTAssertEqual(self.items.previousItem(for: NSRange(60..<70)), items[3])
|
||||
#expect(self.items.previousItem(for: NSRange(10..<20)) == nil)
|
||||
#expect(self.items.previousItem(for: NSRange(19..<19)) == nil)
|
||||
#expect(self.items.previousItem(for: NSRange(59..<70)) == items[0])
|
||||
#expect(self.items.previousItem(for: NSRange(60..<70)) == items[3])
|
||||
}
|
||||
|
||||
|
||||
func testNextItem() throws {
|
||||
@Test func nextItem() throws {
|
||||
|
||||
XCTAssertNil(self.emptyItems.nextItem(for: NSRange(10..<20)))
|
||||
#expect(self.emptyItems.nextItem(for: NSRange(10..<20)) == nil)
|
||||
|
||||
XCTAssertEqual(self.items.nextItem(for: NSRange(0..<0)), items[0])
|
||||
XCTAssertEqual(self.items.nextItem(for: NSRange(0..<10)), items[3])
|
||||
XCTAssertEqual(self.items.nextItem(for: NSRange(40..<40)), items[5])
|
||||
XCTAssertNil(self.items.nextItem(for: NSRange(60..<60)))
|
||||
XCTAssertNil(self.items.nextItem(for: NSRange(40..<61)))
|
||||
#expect(self.items.nextItem(for: NSRange(0..<0)) == items[0])
|
||||
#expect(self.items.nextItem(for: NSRange(0..<10)) == items[3])
|
||||
#expect(self.items.nextItem(for: NSRange(40..<40)) == items[5])
|
||||
#expect(self.items.nextItem(for: NSRange(60..<60)) == nil)
|
||||
#expect(self.items.nextItem(for: NSRange(40..<61)) == nil)
|
||||
}
|
||||
|
||||
|
||||
func testFilter() throws {
|
||||
@Test func filter() throws {
|
||||
|
||||
XCTAssertEqual(self.items.compactMap { $0.filter("", keyPath: \.title) }.count, 7)
|
||||
XCTAssertEqual(self.items.compactMap { $0.filter("cat", keyPath: \.title) }.count, 0)
|
||||
XCTAssertEqual(self.items.compactMap { $0.filter("dog", keyPath: \.title) }.count, 2)
|
||||
XCTAssertEqual(self.items.compactMap { $0.filter("dow", keyPath: \.title) }.count, 1)
|
||||
#expect(self.items.compactMap { $0.filter("", keyPath: \.title) }.count == 7)
|
||||
#expect(self.items.compactMap { $0.filter("cat", keyPath: \.title) }.count == 0)
|
||||
#expect(self.items.compactMap { $0.filter("dog", keyPath: \.title) }.count == 2)
|
||||
#expect(self.items.compactMap { $0.filter("dow", keyPath: \.title) }.count == 1)
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2022-2023 1024jp
|
||||
// © 2022-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -23,64 +23,68 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class RegularExpressionSyntaxTests: XCTestCase {
|
||||
struct RegularExpressionSyntaxTests {
|
||||
|
||||
func testBracketHighlight() throws {
|
||||
@Test func highlightBracket() throws {
|
||||
|
||||
// -> Only the `]` at the first position will be evaluated as a character.
|
||||
|
||||
let character = RegularExpressionSyntaxType.character
|
||||
|
||||
XCTAssertEqual(character.ranges(in: "[abc]"), [NSRange(location: 1, length: 3)])
|
||||
XCTAssertEqual(character.ranges(in: "\\[a[a]"), [NSRange(location: 0, length: 2), NSRange(location: 4, length: 1)])
|
||||
XCTAssertEqual(character.ranges(in: "[a\\]]"), [NSRange(location: 2, length: 2), NSRange(location: 1, length: 3)])
|
||||
XCTAssertEqual(character.ranges(in: "[]]"), [NSRange(location: 1, length: 1)])
|
||||
XCTAssertEqual(character.ranges(in: "[a]]"), [NSRange(location: 1, length: 1)])
|
||||
XCTAssertEqual(character.ranges(in: "[]a]"), [NSRange(location: 1, length: 2)])
|
||||
XCTAssertEqual(character.ranges(in: "[a]b]"), [NSRange(location: 1, length: 1)])
|
||||
#expect(character.ranges(in: "[abc]") == [NSRange(location: 1, length: 3)])
|
||||
#expect(character.ranges(in: "\\[a[a]") == [NSRange(location: 0, length: 2), NSRange(location: 4, length: 1)])
|
||||
#expect(character.ranges(in: "[a\\]]") == [NSRange(location: 2, length: 2), NSRange(location: 1, length: 3)])
|
||||
#expect(character.ranges(in: "[]]") == [NSRange(location: 1, length: 1)])
|
||||
#expect(character.ranges(in: "[a]]") == [NSRange(location: 1, length: 1)])
|
||||
#expect(character.ranges(in: "[]a]") == [NSRange(location: 1, length: 2)])
|
||||
#expect(character.ranges(in: "[a]b]") == [NSRange(location: 1, length: 1)])
|
||||
|
||||
XCTAssertEqual(character.ranges(in: "[a] [b]"), [NSRange(location: 1, length: 1),
|
||||
NSRange(location: 5, length: 1)])
|
||||
#expect(character.ranges(in: "[a] [b]") == [NSRange(location: 1, length: 1),
|
||||
NSRange(location: 5, length: 1)])
|
||||
|
||||
XCTAssertEqual(character.ranges(in: "[^a]"), [NSRange(location: 2, length: 1)])
|
||||
XCTAssertEqual(character.ranges(in: "[^^]"), [NSRange(location: 2, length: 1)])
|
||||
XCTAssertEqual(character.ranges(in: "[^]]"), [NSRange(location: 2, length: 1)])
|
||||
XCTAssertEqual(character.ranges(in: "[^]]]"), [NSRange(location: 2, length: 1)])
|
||||
XCTAssertEqual(character.ranges(in: "[^a]]"), [NSRange(location: 2, length: 1)])
|
||||
XCTAssertEqual(character.ranges(in: "[^]a]"), [NSRange(location: 2, length: 2)])
|
||||
XCTAssertEqual(character.ranges(in: "[^a]b]"), [NSRange(location: 2, length: 1)])
|
||||
#expect(character.ranges(in: "[^a]") == [NSRange(location: 2, length: 1)])
|
||||
#expect(character.ranges(in: "[^^]") == [NSRange(location: 2, length: 1)])
|
||||
#expect(character.ranges(in: "[^]]") == [NSRange(location: 2, length: 1)])
|
||||
#expect(character.ranges(in: "[^]]]") == [NSRange(location: 2, length: 1)])
|
||||
#expect(character.ranges(in: "[^a]]") == [NSRange(location: 2, length: 1)])
|
||||
#expect(character.ranges(in: "[^]a]") == [NSRange(location: 2, length: 2)])
|
||||
#expect(character.ranges(in: "[^a]b]") == [NSRange(location: 2, length: 1)])
|
||||
|
||||
// just containing ranges for `\[`
|
||||
XCTAssertEqual(character.ranges(in: "(?<=\\[)a]"), [NSRange(location: 4, length: 2)])
|
||||
#expect(character.ranges(in: "(?<=\\[)a]") == [NSRange(location: 4, length: 2)])
|
||||
}
|
||||
|
||||
|
||||
@Test func highlightSymbol() {
|
||||
|
||||
let symbol = RegularExpressionSyntaxType.symbol
|
||||
|
||||
XCTAssertEqual(symbol.ranges(in: "[abc]"), [NSRange(location: 0, length: 5)])
|
||||
XCTAssertEqual(symbol.ranges(in: "\\[a[a]"), [NSRange(location: 3, length: 3)])
|
||||
XCTAssertEqual(symbol.ranges(in: "[a\\]]"), [NSRange(location: 0, length: 5)])
|
||||
XCTAssertEqual(symbol.ranges(in: "[]]"), [NSRange(location: 0, length: 3)])
|
||||
XCTAssertEqual(symbol.ranges(in: "[a]]"), [NSRange(location: 0, length: 3)])
|
||||
XCTAssertEqual(symbol.ranges(in: "[]a]"), [NSRange(location: 0, length: 4)])
|
||||
XCTAssertEqual(symbol.ranges(in: "[a]b]"), [NSRange(location: 0, length: 3)])
|
||||
#expect(symbol.ranges(in: "[abc]") == [NSRange(location: 0, length: 5)])
|
||||
#expect(symbol.ranges(in: "\\[a[a]") == [NSRange(location: 3, length: 3)])
|
||||
#expect(symbol.ranges(in: "[a\\]]") == [NSRange(location: 0, length: 5)])
|
||||
#expect(symbol.ranges(in: "[]]") == [NSRange(location: 0, length: 3)])
|
||||
#expect(symbol.ranges(in: "[a]]") == [NSRange(location: 0, length: 3)])
|
||||
#expect(symbol.ranges(in: "[]a]") == [NSRange(location: 0, length: 4)])
|
||||
#expect(symbol.ranges(in: "[a]b]") == [NSRange(location: 0, length: 3)])
|
||||
|
||||
XCTAssertEqual(symbol.ranges(in: "[a] [b]"), [NSRange(location: 0, length: 3),
|
||||
NSRange(location: 4, length: 3)])
|
||||
#expect(symbol.ranges(in: "[a] [b]") == [NSRange(location: 0, length: 3),
|
||||
NSRange(location: 4, length: 3)])
|
||||
|
||||
XCTAssertEqual(symbol.ranges(in: "[^a]"), [NSRange(location: 0, length: 4)])
|
||||
XCTAssertEqual(symbol.ranges(in: "[^^]"), [NSRange(location: 0, length: 4)])
|
||||
XCTAssertEqual(symbol.ranges(in: "[^]]"), [NSRange(location: 0, length: 4)])
|
||||
XCTAssertEqual(symbol.ranges(in: "[^]]]"), [NSRange(location: 0, length: 4)])
|
||||
XCTAssertEqual(symbol.ranges(in: "[^a]]"), [NSRange(location: 0, length: 4)])
|
||||
XCTAssertEqual(symbol.ranges(in: "[^]a]"), [NSRange(location: 0, length: 5)])
|
||||
XCTAssertEqual(symbol.ranges(in: "[^a]b]"), [NSRange(location: 0, length: 4)])
|
||||
#expect(symbol.ranges(in: "[^a]") == [NSRange(location: 0, length: 4)])
|
||||
#expect(symbol.ranges(in: "[^^]") == [NSRange(location: 0, length: 4)])
|
||||
#expect(symbol.ranges(in: "[^]]") == [NSRange(location: 0, length: 4)])
|
||||
#expect(symbol.ranges(in: "[^]]]") == [NSRange(location: 0, length: 4)])
|
||||
#expect(symbol.ranges(in: "[^a]]") == [NSRange(location: 0, length: 4)])
|
||||
#expect(symbol.ranges(in: "[^]a]") == [NSRange(location: 0, length: 5)])
|
||||
#expect(symbol.ranges(in: "[^a]b]") == [NSRange(location: 0, length: 4)])
|
||||
|
||||
// just containing ranges for `(?<=`, `(` and `)`
|
||||
XCTAssertEqual(symbol.ranges(in: "(?<=\\[)a]"), [NSRange(location: 0, length: 4),
|
||||
NSRange(location: 0, length: 1),
|
||||
NSRange(location: 6, length: 1)])
|
||||
#expect(symbol.ranges(in: "(?<=\\[)a]") == [NSRange(location: 0, length: 4),
|
||||
NSRange(location: 0, length: 1),
|
||||
NSRange(location: 6, length: 1)])
|
||||
}
|
||||
}
|
||||
|
@ -23,59 +23,64 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class ShiftJISTests: XCTestCase {
|
||||
struct ShiftJISTests {
|
||||
|
||||
func testIANACharSetNames() {
|
||||
@Test func ianaCharSetNames() {
|
||||
|
||||
XCTAssertEqual(ShiftJIS.shiftJIS.ianaCharSet, "shift_jis")
|
||||
XCTAssertEqual(ShiftJIS.shiftJIS_X0213.ianaCharSet, "Shift_JIS")
|
||||
XCTAssertEqual(ShiftJIS.macJapanese.ianaCharSet, "x-mac-japanese")
|
||||
XCTAssertEqual(ShiftJIS.dosJapanese.ianaCharSet, "cp932")
|
||||
#expect(ShiftJIS.shiftJIS.ianaCharSet == "shift_jis")
|
||||
#expect(ShiftJIS.shiftJIS_X0213.ianaCharSet == "Shift_JIS")
|
||||
#expect(ShiftJIS.macJapanese.ianaCharSet == "x-mac-japanese")
|
||||
#expect(ShiftJIS.dosJapanese.ianaCharSet == "cp932")
|
||||
|
||||
XCTAssertEqual(ShiftJIS(ianaCharSetName: ShiftJIS.shiftJIS.ianaCharSet!), .shiftJIS)
|
||||
XCTAssertEqual(ShiftJIS(ianaCharSetName: ShiftJIS.shiftJIS_X0213.ianaCharSet!), .shiftJIS)
|
||||
#expect(ShiftJIS(ianaCharSetName: ShiftJIS.shiftJIS.ianaCharSet!) == .shiftJIS)
|
||||
#expect(ShiftJIS(ianaCharSetName: ShiftJIS.shiftJIS_X0213.ianaCharSet!) == .shiftJIS)
|
||||
}
|
||||
|
||||
|
||||
func testTildaEncoding() {
|
||||
@Test func encodeTilda() {
|
||||
|
||||
XCTAssertEqual(ShiftJIS.shiftJIS.encode("~"), "?")
|
||||
XCTAssertEqual(ShiftJIS.shiftJIS_X0213.encode("~"), "〜")
|
||||
XCTAssertEqual(ShiftJIS.macJapanese.encode("~"), "~")
|
||||
XCTAssertEqual(ShiftJIS.dosJapanese.encode("~"), "~")
|
||||
#expect(ShiftJIS.shiftJIS.encode("~") == "?")
|
||||
#expect(ShiftJIS.shiftJIS_X0213.encode("~") == "〜")
|
||||
#expect(ShiftJIS.macJapanese.encode("~") == "~")
|
||||
#expect(ShiftJIS.dosJapanese.encode("~") == "~")
|
||||
}
|
||||
|
||||
|
||||
func testBackslashEncoding() {
|
||||
@Test func encodeBackslash() {
|
||||
|
||||
XCTAssertEqual(ShiftJIS.shiftJIS.encode("\\"), "\")
|
||||
XCTAssertEqual(ShiftJIS.shiftJIS_X0213.encode("\\"), "\")
|
||||
XCTAssertEqual(ShiftJIS.macJapanese.encode("\\"), "\\")
|
||||
XCTAssertEqual(ShiftJIS.dosJapanese.encode("\\"), "\\")
|
||||
#expect(ShiftJIS.shiftJIS.encode("\\") == "\")
|
||||
#expect(ShiftJIS.shiftJIS_X0213.encode("\\") == "\")
|
||||
#expect(ShiftJIS.macJapanese.encode("\\") == "\\")
|
||||
#expect(ShiftJIS.dosJapanese.encode("\\") == "\\")
|
||||
}
|
||||
|
||||
|
||||
func testYenEncoding() {
|
||||
@Test func encodeYen() {
|
||||
|
||||
XCTAssertEqual(ShiftJIS.shiftJIS.encode("¥"), "¥")
|
||||
XCTAssertEqual(ShiftJIS.shiftJIS_X0213.encode("¥"), "¥")
|
||||
XCTAssertEqual(ShiftJIS.macJapanese.encode("¥"), "¥")
|
||||
XCTAssertEqual(ShiftJIS.dosJapanese.encode("¥"), "?")
|
||||
#expect(ShiftJIS.shiftJIS.encode("¥") == "¥")
|
||||
#expect(ShiftJIS.shiftJIS_X0213.encode("¥") == "¥")
|
||||
#expect(ShiftJIS.macJapanese.encode("¥") == "¥")
|
||||
#expect(ShiftJIS.dosJapanese.encode("¥") == "?")
|
||||
}
|
||||
|
||||
|
||||
func testYenConversion() {
|
||||
@Test func convertYen() {
|
||||
|
||||
XCTAssertEqual("¥".convertYenSign(for: ShiftJIS.shiftJIS.encoding), "¥")
|
||||
XCTAssertEqual("¥".convertYenSign(for: ShiftJIS.shiftJIS_X0213.encoding), "¥")
|
||||
XCTAssertEqual("¥".convertYenSign(for: ShiftJIS.macJapanese.encoding), "¥")
|
||||
XCTAssertEqual("¥".convertYenSign(for: ShiftJIS.dosJapanese.encoding), "\\")
|
||||
#expect("¥".convertYenSign(for: ShiftJIS.shiftJIS.encoding) == "¥")
|
||||
#expect("¥".convertYenSign(for: ShiftJIS.shiftJIS_X0213.encoding) == "¥")
|
||||
#expect("¥".convertYenSign(for: ShiftJIS.macJapanese.encoding) == "¥")
|
||||
#expect("¥".convertYenSign(for: ShiftJIS.dosJapanese.encoding) == "\\")
|
||||
}
|
||||
|
||||
|
||||
@Test(arguments: ShiftJIS.allCases)
|
||||
private func convertYen(shiftJIS: ShiftJIS) {
|
||||
|
||||
ShiftJIS.allCases
|
||||
.forEach { XCTAssertEqual("¥".convertYenSign(for: $0.encoding) == "¥", $0.encode("¥") == "¥") }
|
||||
#expect(("¥".convertYenSign(for: shiftJIS.encoding) == "¥") == (shiftJIS.encode("¥") == "¥"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2016-2023 1024jp
|
||||
// © 2016-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -24,94 +24,95 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import AppKit
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class ShortcutTests: XCTestCase {
|
||||
struct ShortcutTests {
|
||||
|
||||
func testEquivalent() {
|
||||
@Test func equivalent() {
|
||||
|
||||
XCTAssertEqual(Shortcut("A", modifiers: [.control]),
|
||||
Shortcut("a", modifiers: [.control, .shift]))
|
||||
#expect(Shortcut("A", modifiers: [.control]) ==
|
||||
Shortcut("a", modifiers: [.control, .shift]))
|
||||
|
||||
XCTAssertEqual(Shortcut(keySpecChars: "^A"),
|
||||
Shortcut(keySpecChars: "^$a"))
|
||||
#expect(Shortcut(keySpecChars: "^A") ==
|
||||
Shortcut(keySpecChars: "^$a"))
|
||||
}
|
||||
|
||||
|
||||
func testKeySpecCharsCreation() {
|
||||
@Test func createKeySpecChars() {
|
||||
|
||||
XCTAssertNil(Shortcut("", modifiers: []))
|
||||
XCTAssertEqual(Shortcut("a", modifiers: [.control, .shift])?.keySpecChars, "^$a")
|
||||
XCTAssertEqual(Shortcut("b", modifiers: [.command, .option])?.keySpecChars, "~@b")
|
||||
XCTAssertEqual(Shortcut("A", modifiers: [.control])?.keySpecChars, "^$a") // uppercase for Shift key
|
||||
XCTAssertEqual(Shortcut("a", modifiers: [.control, .shift])?.keySpecChars, "^$a")
|
||||
#expect(Shortcut("", modifiers: []) == nil)
|
||||
#expect(Shortcut("a", modifiers: [.control, .shift])?.keySpecChars == "^$a")
|
||||
#expect(Shortcut("b", modifiers: [.command, .option])?.keySpecChars == "~@b")
|
||||
#expect(Shortcut("A", modifiers: [.control])?.keySpecChars == "^$a") // uppercase for Shift key
|
||||
#expect(Shortcut("a", modifiers: [.control, .shift])?.keySpecChars == "^$a")
|
||||
|
||||
XCTAssertEqual(Shortcut("a", modifiers: [])?.keySpecChars, "a")
|
||||
XCTAssertEqual(Shortcut("a", modifiers: [])?.isValid, false)
|
||||
XCTAssertNil(Shortcut("", modifiers: [.control, .shift]))
|
||||
XCTAssertEqual(Shortcut("a", modifiers: [.control, .shift])?.isValid, true)
|
||||
XCTAssertEqual(Shortcut("ab", modifiers: [.control, .shift])?.isValid, false)
|
||||
#expect(Shortcut("a", modifiers: [])?.keySpecChars == "a")
|
||||
#expect(Shortcut("a", modifiers: [])?.isValid == false)
|
||||
#expect(Shortcut("", modifiers: [.control, .shift]) == nil)
|
||||
#expect(Shortcut("a", modifiers: [.control, .shift])?.isValid == true)
|
||||
#expect(Shortcut("ab", modifiers: [.control, .shift])?.isValid == false)
|
||||
}
|
||||
|
||||
|
||||
func testStringToShortcut() throws {
|
||||
@Test func stringToShortcut() throws {
|
||||
|
||||
let shortcut = try XCTUnwrap(Shortcut(keySpecChars: "^$a"))
|
||||
let shortcut = try #require(Shortcut(keySpecChars: "^$a"))
|
||||
|
||||
XCTAssertEqual(shortcut.keyEquivalent, "a")
|
||||
XCTAssertEqual(shortcut.modifiers, [.control, .shift])
|
||||
XCTAssert(shortcut.isValid)
|
||||
#expect(shortcut.keyEquivalent == "a")
|
||||
#expect(shortcut.modifiers == [.control, .shift])
|
||||
#expect(shortcut.isValid)
|
||||
}
|
||||
|
||||
|
||||
func testShortcutWithFnKey() throws {
|
||||
@Test func shortcutWithFnKey() throws {
|
||||
|
||||
let shortcut = try XCTUnwrap(Shortcut("a", modifiers: [.function]))
|
||||
let shortcut = try #require(Shortcut("a", modifiers: [.function]))
|
||||
|
||||
XCTAssertFalse(shortcut.isValid)
|
||||
XCTAssertEqual(shortcut.keyEquivalent, "a")
|
||||
XCTAssertEqual(shortcut.modifiers, [.function])
|
||||
XCTAssert(shortcut.symbol == "fn A" || shortcut.symbol == "🌐︎ A")
|
||||
XCTAssertEqual(shortcut.keySpecChars, "a", "The fn key should be ignored.")
|
||||
#expect(!shortcut.isValid)
|
||||
#expect(shortcut.keyEquivalent == "a")
|
||||
#expect(shortcut.modifiers == [.function])
|
||||
#expect(shortcut.symbol == "fn A" || shortcut.symbol == "🌐︎ A")
|
||||
#expect(shortcut.keySpecChars == "a", "The fn key should be ignored.")
|
||||
|
||||
let symbolName = try XCTUnwrap(shortcut.modifierSymbolNames.first)
|
||||
XCTAssertNotNil(NSImage(systemSymbolName: symbolName, accessibilityDescription: nil))
|
||||
let symbolName = try #require(shortcut.modifierSymbolNames.first)
|
||||
#expect(NSImage(systemSymbolName: symbolName, accessibilityDescription: nil) != nil)
|
||||
}
|
||||
|
||||
|
||||
func testMenuItemShortcut() {
|
||||
@Test func menuItemShortcut() {
|
||||
|
||||
let menuItem = NSMenuItem(title: "", action: nil, keyEquivalent: "C")
|
||||
menuItem.keyEquivalentModifierMask = [.command]
|
||||
|
||||
let shortcut = Shortcut(menuItem.keyEquivalent, modifiers: menuItem.keyEquivalentModifierMask)
|
||||
|
||||
XCTAssertEqual(shortcut?.symbol, "⇧ ⌘ C")
|
||||
XCTAssertEqual(shortcut, menuItem.shortcut)
|
||||
#expect(shortcut?.symbol == "⇧ ⌘ C")
|
||||
#expect(shortcut == menuItem.shortcut)
|
||||
}
|
||||
|
||||
|
||||
func testShortcutSymbols() throws {
|
||||
@Test func shortcutSymbols() throws {
|
||||
|
||||
// test modifier symbols
|
||||
XCTAssertNil(Shortcut(keySpecChars: ""))
|
||||
XCTAssertEqual(Shortcut(keySpecChars: "^$a")?.symbol, "^ ⇧ A")
|
||||
XCTAssertEqual(Shortcut(keySpecChars: "~@b")?.symbol, "⌥ ⌘ B")
|
||||
#expect(Shortcut(keySpecChars: "") == nil)
|
||||
#expect(Shortcut(keySpecChars: "^$a")?.symbol == "^ ⇧ A")
|
||||
#expect(Shortcut(keySpecChars: "~@b")?.symbol == "⌥ ⌘ B")
|
||||
|
||||
// test unprintable keys
|
||||
let f10 = try XCTUnwrap(String(NSEvent.SpecialKey.f10.unicodeScalar))
|
||||
XCTAssertEqual(Shortcut(keySpecChars: "@" + f10)?.symbol, "⌘ F10")
|
||||
let f10 = try #require(String(NSEvent.SpecialKey.f10.unicodeScalar))
|
||||
#expect(Shortcut(keySpecChars: "@" + f10)?.symbol == "⌘ F10")
|
||||
|
||||
let delete = try XCTUnwrap(UnicodeScalar(NSDeleteCharacter).flatMap(String.init))
|
||||
XCTAssertEqual(Shortcut(keySpecChars: "@" + delete)?.symbol, "⌘ ⌫")
|
||||
let delete = try #require(UnicodeScalar(NSDeleteCharacter).flatMap(String.init))
|
||||
#expect(Shortcut(keySpecChars: "@" + delete)?.symbol == "⌘ ⌫")
|
||||
|
||||
// test creation
|
||||
let deleteForward = try XCTUnwrap(String(NSEvent.SpecialKey.deleteForward.unicodeScalar))
|
||||
XCTAssertNil(Shortcut(symbolRepresentation: ""))
|
||||
XCTAssertEqual(Shortcut(symbolRepresentation: "^ ⇧ A")?.keySpecChars, "^$a")
|
||||
XCTAssertEqual(Shortcut(symbolRepresentation: "⌥ ⌘ B")?.keySpecChars, "~@b")
|
||||
XCTAssertEqual(Shortcut(symbolRepresentation: "⌘ F10")?.keySpecChars, "@" + f10)
|
||||
XCTAssertEqual(Shortcut(symbolRepresentation: "⌘ ⌦")?.keySpecChars, "@" + deleteForward)
|
||||
let deleteForward = try #require(String(NSEvent.SpecialKey.deleteForward.unicodeScalar))
|
||||
#expect(Shortcut(symbolRepresentation: "") == nil)
|
||||
#expect(Shortcut(symbolRepresentation: "^ ⇧ A")?.keySpecChars == "^$a")
|
||||
#expect(Shortcut(symbolRepresentation: "⌥ ⌘ B")?.keySpecChars == "~@b")
|
||||
#expect(Shortcut(symbolRepresentation: "⌘ F10")?.keySpecChars == "@" + f10)
|
||||
#expect(Shortcut(symbolRepresentation: "⌘ ⌦")?.keySpecChars == "@" + deleteForward)
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2022-2023 1024jp
|
||||
// © 2022-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -23,22 +23,23 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class SnippetTests: XCTestCase {
|
||||
struct SnippetTests {
|
||||
|
||||
func testSimpleSnippet() {
|
||||
@Test func simpleSnippet() {
|
||||
|
||||
let snippet = Snippet(name: "", format: "<h1><<<SELECTION>>><<<CURSOR>>></h1>")
|
||||
let (string, selections) = snippet.insertion(selectedString: "abc")
|
||||
|
||||
XCTAssertEqual(string, "<h1>abc</h1>")
|
||||
XCTAssertEqual(selections, [NSRange(location: 7, length: 0)])
|
||||
#expect(string == "<h1>abc</h1>")
|
||||
#expect(selections == [NSRange(location: 7, length: 0)])
|
||||
}
|
||||
|
||||
|
||||
func testMultipleLines() {
|
||||
@Test func multipleLines() {
|
||||
|
||||
let format = """
|
||||
<ul>
|
||||
@ -55,9 +56,9 @@ final class SnippetTests: XCTestCase {
|
||||
<li></li>
|
||||
</ul>
|
||||
"""
|
||||
XCTAssertEqual(string, expectedString)
|
||||
XCTAssertEqual(selections, [NSRange(location: 13, length: 0),
|
||||
NSRange(location: 27, length: 0)])
|
||||
#expect(string == expectedString)
|
||||
#expect(selections == [NSRange(location: 13, length: 0),
|
||||
NSRange(location: 27, length: 0)])
|
||||
|
||||
let (indentedString, indentedSelections) = snippet.insertion(selectedString: "", indent: " ")
|
||||
|
||||
@ -67,13 +68,13 @@ final class SnippetTests: XCTestCase {
|
||||
<li></li>
|
||||
</ul>
|
||||
"""
|
||||
XCTAssertEqual(indentedString, expectedIndentString)
|
||||
XCTAssertEqual(indentedSelections, [NSRange(location: 17, length: 0),
|
||||
NSRange(location: 35, length: 0)])
|
||||
#expect(indentedString == expectedIndentString)
|
||||
#expect(indentedSelections == [NSRange(location: 17, length: 0),
|
||||
NSRange(location: 35, length: 0)])
|
||||
}
|
||||
|
||||
|
||||
func testMultipleInsertions() {
|
||||
@Test func multipleInsertions() {
|
||||
|
||||
let string = """
|
||||
aaa
|
||||
@ -95,7 +96,7 @@ final class SnippetTests: XCTestCase {
|
||||
let expectedSelections = [NSRange(location: 11, length: 0),
|
||||
NSRange(location: 21, length: 0),
|
||||
NSRange(location: 33, length: 0)]
|
||||
XCTAssertEqual(strings, expectedStrings)
|
||||
XCTAssertEqual(selections, expectedSelections)
|
||||
#expect(strings == expectedStrings)
|
||||
#expect(selections == expectedSelections)
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2017-2020 1024jp
|
||||
// © 2017-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -24,21 +24,21 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class StringCollectionTests: XCTestCase {
|
||||
struct StringCollectionTests {
|
||||
|
||||
func testAvailableNameCreation() {
|
||||
@Test func createAvailableNames() {
|
||||
|
||||
let names = ["foo", "foo 3", "foo copy 3", "foo 4", "foo 7"]
|
||||
let copy = "copy"
|
||||
|
||||
XCTAssertEqual(names.createAvailableName(for: "foo"), "foo 2")
|
||||
XCTAssertEqual(names.createAvailableName(for: "foo 3"), "foo 5")
|
||||
#expect(names.createAvailableName(for: "foo") == "foo 2")
|
||||
#expect(names.createAvailableName(for: "foo 3") == "foo 5")
|
||||
|
||||
XCTAssertEqual(names.createAvailableName(for: "foo", suffix: copy), "foo copy")
|
||||
XCTAssertEqual(names.createAvailableName(for: "foo 3", suffix: copy), "foo 3 copy")
|
||||
XCTAssertEqual(names.createAvailableName(for: "foo copy 3", suffix: copy), "foo copy 4")
|
||||
#expect(names.createAvailableName(for: "foo", suffix: copy) == "foo copy")
|
||||
#expect(names.createAvailableName(for: "foo 3", suffix: copy) == "foo 3 copy")
|
||||
#expect(names.createAvailableName(for: "foo copy 3", suffix: copy) == "foo copy 4")
|
||||
}
|
||||
}
|
||||
|
@ -24,117 +24,118 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import AppKit
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class StringCommentingTests: XCTestCase {
|
||||
struct StringCommentingTests {
|
||||
|
||||
// MARK: String extension Tests
|
||||
|
||||
func testInlineCommentOut() {
|
||||
@Test func inlineCommentOut() {
|
||||
|
||||
XCTAssertEqual("foo".inlineCommentOut(delimiter: "//", ranges: []), [])
|
||||
#expect("foo".inlineCommentOut(delimiter: "//", ranges: []).isEmpty)
|
||||
|
||||
XCTAssertEqual("foo".inlineCommentOut(delimiter: "//", ranges: [NSRange(0..<0)]),
|
||||
[.init(string: "//", location: 0, forward: true)])
|
||||
XCTAssertEqual("foo".inlineCommentOut(delimiter: "//", ranges: [NSRange(1..<2)]),
|
||||
[.init(string: "//", location: 1, forward: true)])
|
||||
#expect("foo".inlineCommentOut(delimiter: "//", ranges: [NSRange(0..<0)]) ==
|
||||
[.init(string: "//", location: 0, forward: true)])
|
||||
#expect("foo".inlineCommentOut(delimiter: "//", ranges: [NSRange(1..<2)]) ==
|
||||
[.init(string: "//", location: 1, forward: true)])
|
||||
}
|
||||
|
||||
|
||||
func testBlockCommentOut() {
|
||||
@Test func blockCommentOut() {
|
||||
|
||||
XCTAssertEqual("foo".blockCommentOut(delimiters: Pair("<-", "->"), ranges: []), [])
|
||||
#expect("foo".blockCommentOut(delimiters: Pair("<-", "->"), ranges: []).isEmpty)
|
||||
|
||||
XCTAssertEqual("foo".blockCommentOut(delimiters: Pair("<-", "->"), ranges: [NSRange(0..<0)]),
|
||||
[.init(string: "<-", location: 0, forward: true), .init(string: "->", location: 0, forward: false)])
|
||||
#expect("foo".blockCommentOut(delimiters: Pair("<-", "->"), ranges: [NSRange(0..<0)]) ==
|
||||
[.init(string: "<-", location: 0, forward: true), .init(string: "->", location: 0, forward: false)])
|
||||
}
|
||||
|
||||
|
||||
func testInlineUncomment() {
|
||||
@Test func inlineUncomment() {
|
||||
|
||||
XCTAssertEqual("foo".rangesOfInlineDelimiter("//", ranges: []), [])
|
||||
XCTAssertEqual("foo".rangesOfInlineDelimiter("//", ranges: [NSRange(0..<0)]), [])
|
||||
#expect("foo".rangesOfInlineDelimiter("//", ranges: [])?.isEmpty == true)
|
||||
#expect("foo".rangesOfInlineDelimiter("//", ranges: [NSRange(0..<0)])?.isEmpty == true)
|
||||
|
||||
XCTAssertEqual("//foo".rangesOfInlineDelimiter("//", ranges: [NSRange(0..<5)]), [NSRange(0..<2)])
|
||||
XCTAssertEqual("// foo".rangesOfInlineDelimiter("//", ranges: [NSRange(0..<5)]), [NSRange(0..<2)])
|
||||
#expect("//foo".rangesOfInlineDelimiter("//", ranges: [NSRange(0..<5)]) == [NSRange(0..<2)])
|
||||
#expect("// foo".rangesOfInlineDelimiter("//", ranges: [NSRange(0..<5)]) == [NSRange(0..<2)])
|
||||
|
||||
XCTAssertEqual(" //foo".rangesOfInlineDelimiter("//", ranges: [NSRange(0..<7)]), [NSRange(2..<4)])
|
||||
#expect(" //foo".rangesOfInlineDelimiter("//", ranges: [NSRange(0..<7)]) == [NSRange(2..<4)])
|
||||
}
|
||||
|
||||
|
||||
func testBlockUncomment() {
|
||||
@Test func blockUncomment() {
|
||||
|
||||
XCTAssertEqual("foo".rangesOfBlockDelimiters(Pair("<-", "->"), ranges: []), [])
|
||||
XCTAssertEqual("foo".rangesOfBlockDelimiters(Pair("<-", "->"), ranges: [NSRange(0..<0)]), [])
|
||||
#expect("foo".rangesOfBlockDelimiters(Pair("<-", "->"), ranges: [])?.isEmpty == true)
|
||||
#expect("foo".rangesOfBlockDelimiters(Pair("<-", "->"), ranges: [NSRange(0..<0)])?.isEmpty == true)
|
||||
|
||||
XCTAssertEqual("<-foo->".rangesOfBlockDelimiters(Pair("<-", "->"), ranges: [NSRange(0..<7)]), [NSRange(0..<2), NSRange(5..<7)])
|
||||
XCTAssertEqual("<- foo ->".rangesOfBlockDelimiters(Pair("<-", "->"), ranges: [NSRange(0..<9)]), [NSRange(0..<2), NSRange(7..<9)])
|
||||
#expect("<-foo->".rangesOfBlockDelimiters(Pair("<-", "->"), ranges: [NSRange(0..<7)]) == [NSRange(0..<2), NSRange(5..<7)])
|
||||
#expect("<- foo ->".rangesOfBlockDelimiters(Pair("<-", "->"), ranges: [NSRange(0..<9)]) == [NSRange(0..<2), NSRange(7..<9)])
|
||||
|
||||
XCTAssertEqual(" <-foo-> ".rangesOfBlockDelimiters(Pair("<-", "->"), ranges: [NSRange(0..<9)]), [NSRange(1..<3), NSRange(6..<8)])
|
||||
XCTAssertNil(" <-foo-> ".rangesOfBlockDelimiters(Pair("<-", "->"), ranges: [NSRange(1..<7)]))
|
||||
#expect(" <-foo-> ".rangesOfBlockDelimiters(Pair("<-", "->"), ranges: [NSRange(0..<9)]) == [NSRange(1..<3), NSRange(6..<8)])
|
||||
#expect(" <-foo-> ".rangesOfBlockDelimiters(Pair("<-", "->"), ranges: [NSRange(1..<7)]) == nil)
|
||||
|
||||
// ok, this is currently in spec, but not a good one...
|
||||
XCTAssertEqual("<-foo-><-bar->".rangesOfBlockDelimiters(Pair("<-", "->"), ranges: [NSRange(0..<14)]), [NSRange(0..<2), NSRange(12..<14)])
|
||||
#expect("<-foo-><-bar->".rangesOfBlockDelimiters(Pair("<-", "->"), ranges: [NSRange(0..<14)]) == [NSRange(0..<2), NSRange(12..<14)])
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: TextView extension Tests
|
||||
|
||||
@MainActor func testTextViewInlineComment() {
|
||||
@MainActor @Test func textViewInlineComment() {
|
||||
|
||||
let textView = CommentingTextView()
|
||||
|
||||
textView.string = "foo\nbar"
|
||||
textView.selectedRanges = [NSRange(0..<3), NSRange(4..<7)] as [NSValue]
|
||||
textView.commentOut(types: .inline, fromLineHead: true)
|
||||
XCTAssertEqual(textView.string, "//foo\n//bar")
|
||||
XCTAssertEqual(textView.selectedRanges, [NSRange(0..<5), NSRange(6..<11)] as [NSValue])
|
||||
XCTAssertTrue(textView.canUncomment(partly: false))
|
||||
#expect(textView.string == "//foo\n//bar")
|
||||
#expect(textView.selectedRanges == [NSRange(0..<5), NSRange(6..<11)] as [NSValue])
|
||||
#expect(textView.canUncomment(partly: false))
|
||||
textView.uncomment()
|
||||
XCTAssertEqual(textView.string, "foo\nbar")
|
||||
XCTAssertEqual(textView.selectedRanges, [NSRange(0..<3), NSRange(4..<7)] as [NSValue])
|
||||
#expect(textView.string == "foo\nbar")
|
||||
#expect(textView.selectedRanges == [NSRange(0..<3), NSRange(4..<7)] as [NSValue])
|
||||
|
||||
textView.selectedRanges = [NSRange(1..<1)] as [NSValue]
|
||||
textView.insertionLocations = [5]
|
||||
textView.commentOut(types: .inline, fromLineHead: true)
|
||||
XCTAssertEqual(textView.string, "//foo\n//bar")
|
||||
XCTAssertEqual(textView.rangesForUserTextChange, [NSRange(3..<3), NSRange(9..<9)] as [NSValue])
|
||||
XCTAssertTrue(textView.canUncomment(partly: false))
|
||||
#expect(textView.string == "//foo\n//bar")
|
||||
#expect(textView.rangesForUserTextChange == [NSRange(3..<3), NSRange(9..<9)] as [NSValue])
|
||||
#expect(textView.canUncomment(partly: false))
|
||||
textView.uncomment()
|
||||
XCTAssertEqual(textView.string, "foo\nbar")
|
||||
XCTAssertEqual(textView.rangesForUserTextChange, [NSRange(1..<1), NSRange(5..<5)] as [NSValue])
|
||||
#expect(textView.string == "foo\nbar")
|
||||
#expect(textView.rangesForUserTextChange == [NSRange(1..<1), NSRange(5..<5)] as [NSValue])
|
||||
}
|
||||
|
||||
|
||||
@MainActor func testTextViewBlockComment() {
|
||||
@MainActor @Test func textViewBlockComment() {
|
||||
|
||||
let textView = CommentingTextView()
|
||||
|
||||
textView.string = "foo\nbar"
|
||||
textView.selectedRanges = [NSRange(0..<3), NSRange(4..<7)] as [NSValue]
|
||||
textView.commentOut(types: .block, fromLineHead: true)
|
||||
XCTAssertEqual(textView.string, "<-foo->\n<-bar->")
|
||||
XCTAssertEqual(textView.selectedRanges, [NSRange(0..<7), NSRange(8..<15)] as [NSValue])
|
||||
XCTAssertTrue(textView.canUncomment(partly: false))
|
||||
#expect(textView.string == "<-foo->\n<-bar->")
|
||||
#expect(textView.selectedRanges == [NSRange(0..<7), NSRange(8..<15)] as [NSValue])
|
||||
#expect(textView.canUncomment(partly: false))
|
||||
textView.uncomment()
|
||||
XCTAssertEqual(textView.string, "foo\nbar")
|
||||
XCTAssertEqual(textView.selectedRanges, [NSRange(0..<3), NSRange(4..<7)] as [NSValue])
|
||||
#expect(textView.string == "foo\nbar")
|
||||
#expect(textView.selectedRanges == [NSRange(0..<3), NSRange(4..<7)] as [NSValue])
|
||||
|
||||
textView.selectedRanges = [NSRange(1..<1)] as [NSValue]
|
||||
textView.insertionLocations = [5]
|
||||
textView.commentOut(types: .block, fromLineHead: true)
|
||||
XCTAssertEqual(textView.string, "<-foo->\n<-bar->")
|
||||
XCTAssertEqual(textView.rangesForUserTextChange, [NSRange(3..<3), NSRange(11..<11)] as [NSValue])
|
||||
XCTAssertTrue(textView.canUncomment(partly: false))
|
||||
#expect(textView.string == "<-foo->\n<-bar->")
|
||||
#expect(textView.rangesForUserTextChange == [NSRange(3..<3), NSRange(11..<11)] as [NSValue])
|
||||
#expect(textView.canUncomment(partly: false))
|
||||
textView.uncomment()
|
||||
XCTAssertEqual(textView.string, "foo\nbar")
|
||||
XCTAssertEqual(textView.rangesForUserTextChange, [NSRange(1..<1), NSRange(5..<5)] as [NSValue])
|
||||
#expect(textView.string == "foo\nbar")
|
||||
#expect(textView.rangesForUserTextChange == [NSRange(1..<1), NSRange(5..<5)] as [NSValue])
|
||||
}
|
||||
|
||||
|
||||
@MainActor func testIncompatibility() {
|
||||
@MainActor @Test func checkIncompatibility() {
|
||||
|
||||
let textView = CommentingTextView()
|
||||
|
||||
@ -144,8 +145,8 @@ final class StringCommentingTests: XCTestCase {
|
||||
// foo bar
|
||||
"""
|
||||
textView.selectedRange = textView.string.nsRange
|
||||
XCTAssertTrue(textView.canUncomment(partly: false))
|
||||
XCTAssertTrue(textView.canUncomment(partly: true))
|
||||
#expect(textView.canUncomment(partly: false))
|
||||
#expect(textView.canUncomment(partly: true))
|
||||
|
||||
textView.string = """
|
||||
// foo
|
||||
@ -153,8 +154,8 @@ final class StringCommentingTests: XCTestCase {
|
||||
// foo bar
|
||||
"""
|
||||
textView.selectedRange = textView.string.nsRange
|
||||
XCTAssertFalse(textView.canUncomment(partly: false))
|
||||
XCTAssertTrue(textView.canUncomment(partly: true))
|
||||
#expect(!textView.canUncomment(partly: false))
|
||||
#expect(textView.canUncomment(partly: true))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,28 +24,27 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class StringExtensionsTests: XCTestCase {
|
||||
struct StringExtensionsTests {
|
||||
|
||||
/// Tests if the U+FEFF omitting bug on Swift 5 still exists.
|
||||
///
|
||||
/// - Bug: <https://bugs.swift.org/browse/SR-10896>
|
||||
func testFEFF() {
|
||||
@Test(.bug("https://bugs.swift.org/browse/SR-10896")) func feff() {
|
||||
|
||||
let bom = "\u{feff}"
|
||||
|
||||
// -> Some of these test cases must fail if the bug fixed.
|
||||
XCTAssertEqual(bom.count, 1)
|
||||
XCTAssertEqual(("\(bom)abc").count, 4)
|
||||
XCTAssertEqual(NSString(string: bom).length, 0) // correct: 1
|
||||
XCTAssertEqual(NSString(string: "\(bom)\(bom)").length, 1) // correct: 2
|
||||
XCTAssertEqual(NSString(string: "\(bom)abc").length, 3) // correct: 4
|
||||
XCTAssertEqual(NSString(string: "a\(bom)bc").length, 4)
|
||||
#expect(bom.count == 1)
|
||||
#expect(("\(bom)abc").count == 4)
|
||||
#expect(NSString(string: bom).length == 0) // correct: 1
|
||||
#expect(NSString(string: "\(bom)\(bom)").length == 1) // correct: 2
|
||||
#expect(NSString(string: "\(bom)abc").length == 3) // correct: 4
|
||||
#expect(NSString(string: "a\(bom)bc").length == 4)
|
||||
|
||||
let string = "\(bom)abc"
|
||||
XCTAssertNotEqual(string.immutable, string) // -> This test must fail if the bug fixed.
|
||||
#expect(string.immutable != string) // -> This test must fail if the bug fixed.
|
||||
|
||||
// Implicit NSString cast is fixed.
|
||||
// -> However, still crashes when `string.immutable.enumerateSubstrings(in:)`
|
||||
@ -54,334 +53,334 @@ final class StringExtensionsTests: XCTestCase {
|
||||
}
|
||||
|
||||
|
||||
func testCharacterEscape() {
|
||||
@Test func escapeCharacter() {
|
||||
|
||||
let string = "a\\a\\\\aa"
|
||||
|
||||
XCTAssertFalse(string.isCharacterEscaped(at: 0))
|
||||
XCTAssertTrue(string.isCharacterEscaped(at: 2))
|
||||
XCTAssertFalse(string.isCharacterEscaped(at: 5))
|
||||
#expect(!string.isCharacterEscaped(at: 0))
|
||||
#expect(string.isCharacterEscaped(at: 2))
|
||||
#expect(!string.isCharacterEscaped(at: 5))
|
||||
}
|
||||
|
||||
|
||||
func testUnescaping() {
|
||||
@Test func unescape() {
|
||||
|
||||
XCTAssertEqual(#"\\"#.unescaped, "\\")
|
||||
XCTAssertEqual(#"\'"#.unescaped, "\'")
|
||||
XCTAssertEqual(#"\""#.unescaped, "\"")
|
||||
XCTAssertEqual(#"a\n "#.unescaped, "a\n ")
|
||||
XCTAssertEqual(#"a\\n "#.unescaped, "a\\n ")
|
||||
XCTAssertEqual(#"a\\\n "#.unescaped, "a\\\n ")
|
||||
XCTAssertEqual(#"a\\\\n"#.unescaped, "a\\\\n")
|
||||
XCTAssertEqual(#"\\\\\t"#.unescaped, "\\\\\t")
|
||||
XCTAssertEqual(#"\\foo\\\\\0bar\\"#.unescaped, "\\foo\\\\\u{0}bar\\")
|
||||
XCTAssertEqual(#"\\\\\\\\foo"#.unescaped, "\\\\\\\\foo")
|
||||
XCTAssertEqual(#"foo: \r\n1"#.unescaped, "foo: \r\n1")
|
||||
#expect(#"\\"#.unescaped == "\\")
|
||||
#expect(#"\'"#.unescaped == "\'")
|
||||
#expect(#"\""#.unescaped == "\"")
|
||||
#expect(#"a\n "#.unescaped == "a\n ")
|
||||
#expect(#"a\\n "#.unescaped == "a\\n ")
|
||||
#expect(#"a\\\n "#.unescaped == "a\\\n ")
|
||||
#expect(#"a\\\\n"#.unescaped == "a\\\\n")
|
||||
#expect(#"\\\\\t"#.unescaped == "\\\\\t")
|
||||
#expect(#"\\foo\\\\\0bar\\"#.unescaped == "\\foo\\\\\u{0}bar\\")
|
||||
#expect(#"\\\\\\\\foo"#.unescaped == "\\\\\\\\foo")
|
||||
#expect(#"foo: \r\n1"#.unescaped == "foo: \r\n1")
|
||||
}
|
||||
|
||||
|
||||
func testComposedCharactersCount() {
|
||||
@Test func countComposedCharacters() {
|
||||
|
||||
// make sure that `String.count` counts characters as I want
|
||||
XCTAssertEqual("foo".count, 3)
|
||||
XCTAssertEqual("\r\n".count, 1)
|
||||
XCTAssertEqual("😀🇯🇵a".count, 3)
|
||||
XCTAssertEqual("😀🏻".count, 1)
|
||||
XCTAssertEqual("👍🏻".count, 1)
|
||||
#expect("foo".count == 3)
|
||||
#expect("\r\n".count == 1)
|
||||
#expect("😀🇯🇵a".count == 3)
|
||||
#expect("😀🏻".count == 1)
|
||||
#expect("👍🏻".count == 1)
|
||||
|
||||
// single regional indicator
|
||||
XCTAssertEqual("🇦 ".count, 2)
|
||||
#expect("🇦 ".count == 2)
|
||||
}
|
||||
|
||||
|
||||
func testWordsCount() {
|
||||
@Test func countWords() {
|
||||
|
||||
XCTAssertEqual("Clarus says moof!".numberOfWords, 3)
|
||||
XCTAssertEqual("plain-text".numberOfWords, 2)
|
||||
XCTAssertEqual("!".numberOfWords, 0)
|
||||
XCTAssertEqual("".numberOfWords, 0)
|
||||
#expect("Clarus says moof!".numberOfWords == 3)
|
||||
#expect("plain-text".numberOfWords == 2)
|
||||
#expect("!".numberOfWords == 0)
|
||||
#expect("".numberOfWords == 0)
|
||||
}
|
||||
|
||||
|
||||
func testLinesCount() {
|
||||
@Test func countLines() {
|
||||
|
||||
XCTAssertEqual("".numberOfLines, 0)
|
||||
XCTAssertEqual("a".numberOfLines, 1)
|
||||
XCTAssertEqual("\n".numberOfLines, 1)
|
||||
XCTAssertEqual("\n\n".numberOfLines, 2)
|
||||
XCTAssertEqual("\u{feff}".numberOfLines, 1)
|
||||
XCTAssertEqual("ab\r\ncd".numberOfLines, 2)
|
||||
#expect("".numberOfLines == 0)
|
||||
#expect("a".numberOfLines == 1)
|
||||
#expect("\n".numberOfLines == 1)
|
||||
#expect("\n\n".numberOfLines == 2)
|
||||
#expect("\u{feff}".numberOfLines == 1)
|
||||
#expect("ab\r\ncd".numberOfLines == 2)
|
||||
|
||||
let testString = "a\nb c\n\n"
|
||||
XCTAssertEqual(testString.numberOfLines, 3)
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<0)), 0) // ""
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<1)), 1) // "a"
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<2)), 1) // "a\n"
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<6)), 2) // "a\nb c\n"
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<7)), 3) // "a\nb c\n\n"
|
||||
#expect(testString.numberOfLines == 3)
|
||||
#expect(testString.numberOfLines(in: NSRange(0..<0)) == 0) // ""
|
||||
#expect(testString.numberOfLines(in: NSRange(0..<1)) == 1) // "a"
|
||||
#expect(testString.numberOfLines(in: NSRange(0..<2)) == 1) // "a\n"
|
||||
#expect(testString.numberOfLines(in: NSRange(0..<6)) == 2) // "a\nb c\n"
|
||||
#expect(testString.numberOfLines(in: NSRange(0..<7)) == 3) // "a\nb c\n\n"
|
||||
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<0), includesLastBreak: true), 0) // ""
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<1), includesLastBreak: true), 1) // "a"
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<2), includesLastBreak: true), 2) // "a\n"
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<6), includesLastBreak: true), 3) // "a\nb c\n"
|
||||
XCTAssertEqual(testString.numberOfLines(in: NSRange(0..<7), includesLastBreak: true), 4) // "a\nb c\n\n"
|
||||
#expect(testString.numberOfLines(in: NSRange(0..<0), includesLastBreak: true) == 0) // ""
|
||||
#expect(testString.numberOfLines(in: NSRange(0..<1), includesLastBreak: true) == 1) // "a"
|
||||
#expect(testString.numberOfLines(in: NSRange(0..<2), includesLastBreak: true) == 2) // "a\n"
|
||||
#expect(testString.numberOfLines(in: NSRange(0..<6), includesLastBreak: true) == 3) // "a\nb c\n"
|
||||
#expect(testString.numberOfLines(in: NSRange(0..<7), includesLastBreak: true) == 4) // "a\nb c\n\n"
|
||||
|
||||
XCTAssertEqual(testString.lineNumber(at: 0), 1)
|
||||
XCTAssertEqual(testString.lineNumber(at: 1), 1)
|
||||
XCTAssertEqual(testString.lineNumber(at: 2), 2)
|
||||
XCTAssertEqual(testString.lineNumber(at: 5), 2)
|
||||
XCTAssertEqual(testString.lineNumber(at: 6), 3)
|
||||
XCTAssertEqual(testString.lineNumber(at: 7), 4)
|
||||
#expect(testString.lineNumber(at: 0) == 1)
|
||||
#expect(testString.lineNumber(at: 1) == 1)
|
||||
#expect(testString.lineNumber(at: 2) == 2)
|
||||
#expect(testString.lineNumber(at: 5) == 2)
|
||||
#expect(testString.lineNumber(at: 6) == 3)
|
||||
#expect(testString.lineNumber(at: 7) == 4)
|
||||
|
||||
let nsString = testString as NSString
|
||||
XCTAssertEqual(nsString.lineNumber(at: 0), testString.lineNumber(at: 0))
|
||||
XCTAssertEqual(nsString.lineNumber(at: 1), testString.lineNumber(at: 1))
|
||||
XCTAssertEqual(nsString.lineNumber(at: 2), testString.lineNumber(at: 2))
|
||||
XCTAssertEqual(nsString.lineNumber(at: 5), testString.lineNumber(at: 5))
|
||||
XCTAssertEqual(nsString.lineNumber(at: 6), testString.lineNumber(at: 6))
|
||||
XCTAssertEqual(nsString.lineNumber(at: 7), testString.lineNumber(at: 7))
|
||||
#expect(nsString.lineNumber(at: 0) == testString.lineNumber(at: 0))
|
||||
#expect(nsString.lineNumber(at: 1) == testString.lineNumber(at: 1))
|
||||
#expect(nsString.lineNumber(at: 2) == testString.lineNumber(at: 2))
|
||||
#expect(nsString.lineNumber(at: 5) == testString.lineNumber(at: 5))
|
||||
#expect(nsString.lineNumber(at: 6) == testString.lineNumber(at: 6))
|
||||
#expect(nsString.lineNumber(at: 7) == testString.lineNumber(at: 7))
|
||||
|
||||
XCTAssertEqual("\u{FEFF}".numberOfLines(in: NSRange(0..<1)), 1) // "\u{FEFF}"
|
||||
XCTAssertEqual("\u{FEFF}\nb".numberOfLines(in: NSRange(0..<3)), 2) // "\u{FEFF}\nb"
|
||||
XCTAssertEqual("a\u{FEFF}\nb".numberOfLines(in: NSRange(1..<4)), 2) // "\u{FEFF}\nb"
|
||||
XCTAssertEqual("a\u{FEFF}\u{FEFF}\nb".numberOfLines(in: NSRange(1..<5)), 2) // "\u{FEFF}\nb"
|
||||
#expect("\u{FEFF}".numberOfLines(in: NSRange(0..<1)) == 1) // "\u{FEFF}"
|
||||
#expect("\u{FEFF}\nb".numberOfLines(in: NSRange(0..<3)) == 2) // "\u{FEFF}\nb"
|
||||
#expect("a\u{FEFF}\nb".numberOfLines(in: NSRange(1..<4)) == 2) // "\u{FEFF}\nb"
|
||||
#expect("a\u{FEFF}\u{FEFF}\nb".numberOfLines(in: NSRange(1..<5)) == 2) // "\u{FEFF}\nb"
|
||||
|
||||
XCTAssertEqual("a\u{FEFF}\nb".numberOfLines, 2)
|
||||
XCTAssertEqual("\u{FEFF}\nb".numberOfLines, 2)
|
||||
XCTAssertEqual("\u{FEFF}0000000000000000".numberOfLines, 1)
|
||||
#expect("a\u{FEFF}\nb".numberOfLines == 2)
|
||||
#expect("\u{FEFF}\nb".numberOfLines == 2)
|
||||
#expect("\u{FEFF}0000000000000000".numberOfLines == 1)
|
||||
|
||||
let bomString = "\u{FEFF}\nb"
|
||||
let range = bomString.startIndex..<bomString.index(bomString.startIndex, offsetBy: 2)
|
||||
XCTAssertEqual(bomString.numberOfLines(in: [range, range]), 1) // "\u{FEFF}\n"
|
||||
#expect(bomString.numberOfLines(in: [range, range]) == 1) // "\u{FEFF}\n"
|
||||
}
|
||||
|
||||
|
||||
func testColumnCount() {
|
||||
@Test func countColumns() {
|
||||
|
||||
let string = "aaa \r\n🐱 "
|
||||
|
||||
XCTAssertEqual(string.columnNumber(at: string.index(string.startIndex, offsetBy: 3)), 3)
|
||||
XCTAssertEqual(string.columnNumber(at: string.index(string.startIndex, offsetBy: 4)), 4)
|
||||
XCTAssertEqual(string.columnNumber(at: string.index(string.startIndex, offsetBy: 5)), 0)
|
||||
XCTAssertEqual(string.columnNumber(at: string.index(string.startIndex, offsetBy: 6)), 1)
|
||||
XCTAssertEqual(string.columnNumber(at: string.index(string.startIndex, offsetBy: 7)), 2)
|
||||
#expect(string.columnNumber(at: string.index(string.startIndex, offsetBy: 3)) == 3)
|
||||
#expect(string.columnNumber(at: string.index(string.startIndex, offsetBy: 4)) == 4)
|
||||
#expect(string.columnNumber(at: string.index(string.startIndex, offsetBy: 5)) == 0)
|
||||
#expect(string.columnNumber(at: string.index(string.startIndex, offsetBy: 6)) == 1)
|
||||
#expect(string.columnNumber(at: string.index(string.startIndex, offsetBy: 7)) == 2)
|
||||
}
|
||||
|
||||
|
||||
func testCharacterCountOptions() {
|
||||
@Test func countCharactersWithOptions() {
|
||||
|
||||
var options = CharacterCountOptions()
|
||||
|
||||
let string = "aaa \t 🐱\n\r\n c"
|
||||
|
||||
XCTAssertEqual(string.count(options: options), string.count)
|
||||
#expect(string.count(options: options) == string.count)
|
||||
options.ignoresNewlines = true
|
||||
XCTAssertEqual(string.count(options: options), 9)
|
||||
#expect(string.count(options: options) == 9)
|
||||
options.ignoresWhitespaces = true
|
||||
XCTAssertEqual(string.count(options: options), 5)
|
||||
#expect(string.count(options: options) == 5)
|
||||
options.ignoresNewlines = false
|
||||
options.ignoresWhitespaces = true
|
||||
XCTAssertEqual(string.count(options: options), 7)
|
||||
#expect(string.count(options: options) == 7)
|
||||
|
||||
// test .treatsConsecutiveWhitespaceAsSingle
|
||||
options = .init()
|
||||
options.treatsConsecutiveWhitespaceAsSingle = true
|
||||
XCTAssertEqual(string.count(options: options), 7)
|
||||
#expect(string.count(options: options) == 7)
|
||||
options.ignoresNewlines = true
|
||||
XCTAssertEqual(string.count(options: options), 7)
|
||||
#expect(string.count(options: options) == 7)
|
||||
options.treatsConsecutiveWhitespaceAsSingle = false
|
||||
options.ignoresNewlines = true
|
||||
options.ignoresWhitespaces = true
|
||||
XCTAssertEqual(string.count(options: options), 5)
|
||||
#expect(string.count(options: options) == 5)
|
||||
|
||||
// test other units
|
||||
options = .init()
|
||||
options.unit = .unicodeScalar
|
||||
XCTAssertEqual(string.count(options: options), 12)
|
||||
#expect(string.count(options: options) == 12)
|
||||
options.unit = .utf16
|
||||
XCTAssertEqual(string.count(options: options), 13)
|
||||
#expect(string.count(options: options) == 13)
|
||||
|
||||
// test normalization
|
||||
let aUmlaut = "Ä"
|
||||
options = .init()
|
||||
options.unit = .unicodeScalar
|
||||
XCTAssertEqual(aUmlaut.count(options: options), 2)
|
||||
#expect(aUmlaut.count(options: options) == 2)
|
||||
options.normalizationForm = .nfc
|
||||
XCTAssertEqual(aUmlaut.count(options: options), 1)
|
||||
#expect(aUmlaut.count(options: options) == 1)
|
||||
}
|
||||
|
||||
|
||||
func testByteCountOptions() {
|
||||
@Test func countBytes() {
|
||||
|
||||
let string = "abc犬牛"
|
||||
var options = CharacterCountOptions(unit: .byte)
|
||||
|
||||
options.encoding = .utf8
|
||||
XCTAssertEqual(string.count(options: options), 9)
|
||||
#expect(string.count(options: options) == 9)
|
||||
|
||||
options.encoding = .shiftJIS
|
||||
XCTAssertEqual(string.count(options: options), 7)
|
||||
#expect(string.count(options: options) == 7)
|
||||
|
||||
options.encoding = .ascii
|
||||
XCTAssertNil(string.count(options: options))
|
||||
#expect(string.count(options: options) == nil)
|
||||
|
||||
options.encoding = .nonLossyASCII
|
||||
XCTAssertEqual(string.count(options: options), 15)
|
||||
#expect(string.count(options: options) == 15)
|
||||
}
|
||||
|
||||
|
||||
func testProgrammingCases() {
|
||||
@Test func codingCases() {
|
||||
|
||||
XCTAssertEqual("AbcDefg Hij".snakecased, "abc_defg hij")
|
||||
XCTAssertEqual("abcDefg Hij".snakecased, "abc_defg hij")
|
||||
XCTAssertEqual("_abcDefg Hij".snakecased, "_abc_defg hij")
|
||||
XCTAssertEqual("AA\u{0308}".snakecased, "a_a\u{0308}")
|
||||
XCTAssertEqual("abÄb".snakecased, "ab_äb")
|
||||
#expect("AbcDefg Hij".snakecased == "abc_defg hij")
|
||||
#expect("abcDefg Hij".snakecased == "abc_defg hij")
|
||||
#expect("_abcDefg Hij".snakecased == "_abc_defg hij")
|
||||
#expect("AA\u{0308}".snakecased == "a_a\u{0308}")
|
||||
#expect("abÄb".snakecased == "ab_äb")
|
||||
|
||||
XCTAssertEqual("abc_defg Hij".camelcased, "abcDefg hij")
|
||||
XCTAssertEqual("AbcDefg Hij".camelcased, "abcDefg hij")
|
||||
XCTAssertEqual("_abcDefg Hij".camelcased, "_abcDefg hij")
|
||||
XCTAssertEqual("a_a\u{0308}".camelcased, "aA\u{0308}")
|
||||
#expect("abc_defg Hij".camelcased == "abcDefg hij")
|
||||
#expect("AbcDefg Hij".camelcased == "abcDefg hij")
|
||||
#expect("_abcDefg Hij".camelcased == "_abcDefg hij")
|
||||
#expect("a_a\u{0308}".camelcased == "aA\u{0308}")
|
||||
|
||||
XCTAssertEqual("abc_defg Hij".pascalcased, "AbcDefg Hij")
|
||||
XCTAssertEqual("abcDefg Hij".pascalcased, "AbcDefg Hij")
|
||||
XCTAssertEqual("_abcDefg Hij".pascalcased, "_abcDefg Hij")
|
||||
XCTAssertEqual("a_a\u{0308}".pascalcased, "AA\u{0308}")
|
||||
#expect("abc_defg Hij".pascalcased == "AbcDefg Hij")
|
||||
#expect("abcDefg Hij".pascalcased == "AbcDefg Hij")
|
||||
#expect("_abcDefg Hij".pascalcased == "_abcDefg Hij")
|
||||
#expect("a_a\u{0308}".pascalcased == "AA\u{0308}")
|
||||
}
|
||||
|
||||
|
||||
func testJapaneseTransform() {
|
||||
@Test func japaneseTransform() {
|
||||
|
||||
let testString = "犬 イヌ いぬ Inu Dog 123 123"
|
||||
|
||||
XCTAssertEqual(testString.fullwidthRoman(reverse: false), "犬 イヌ いぬ Inu Dog 123 123")
|
||||
XCTAssertEqual(testString.fullwidthRoman(reverse: true), "犬 イヌ いぬ Inu Dog 123 123")
|
||||
#expect(testString.fullwidthRoman(reverse: false) == "犬 イヌ いぬ Inu Dog 123 123")
|
||||
#expect(testString.fullwidthRoman(reverse: true) == "犬 イヌ いぬ Inu Dog 123 123")
|
||||
}
|
||||
|
||||
|
||||
func testBeforeIndex() {
|
||||
@Test func beforeIndex() {
|
||||
|
||||
XCTAssertEqual(("00" as NSString).index(before: 0), 0)
|
||||
XCTAssertEqual(("00" as NSString).index(before: 1), 0)
|
||||
XCTAssertEqual(("00" as NSString).index(before: 2), 1)
|
||||
XCTAssertEqual(("0🇦🇦00" as NSString).index(before: 1), 0)
|
||||
XCTAssertEqual(("0🇦🇦00" as NSString).index(before: 2), 1)
|
||||
XCTAssertEqual(("0🇦🇦00" as NSString).index(before: 5), 1)
|
||||
XCTAssertEqual(("0🇦🇦00" as NSString).index(before: 6), 5)
|
||||
#expect(("00" as NSString).index(before: 0) == 0)
|
||||
#expect(("00" as NSString).index(before: 1) == 0)
|
||||
#expect(("00" as NSString).index(before: 2) == 1)
|
||||
#expect(("0🇦🇦00" as NSString).index(before: 1) == 0)
|
||||
#expect(("0🇦🇦00" as NSString).index(before: 2) == 1)
|
||||
#expect(("0🇦🇦00" as NSString).index(before: 5) == 1)
|
||||
#expect(("0🇦🇦00" as NSString).index(before: 6) == 5)
|
||||
|
||||
XCTAssertEqual(("0\r\n0" as NSString).index(before: 3), 1)
|
||||
XCTAssertEqual(("0\r\n0" as NSString).index(before: 2), 1)
|
||||
XCTAssertEqual(("0\r\n0" as NSString).index(before: 1), 0)
|
||||
XCTAssertEqual(("0\n" as NSString).index(before: 1), 0)
|
||||
XCTAssertEqual(("0\n" as NSString).index(before: 2), 1)
|
||||
#expect(("0\r\n0" as NSString).index(before: 3) == 1)
|
||||
#expect(("0\r\n0" as NSString).index(before: 2) == 1)
|
||||
#expect(("0\r\n0" as NSString).index(before: 1) == 0)
|
||||
#expect(("0\n" as NSString).index(before: 1) == 0)
|
||||
#expect(("0\n" as NSString).index(before: 2) == 1)
|
||||
}
|
||||
|
||||
|
||||
func testAfterIndex() {
|
||||
@Test func afterIndex() {
|
||||
|
||||
XCTAssertEqual(("00" as NSString).index(after: 0), 1)
|
||||
XCTAssertEqual(("00" as NSString).index(after: 1), 2)
|
||||
XCTAssertEqual(("00" as NSString).index(after: 2), 2)
|
||||
XCTAssertEqual(("0🇦🇦0" as NSString).index(after: 0), 1)
|
||||
XCTAssertEqual(("0🇦🇦0" as NSString).index(after: 1), 5)
|
||||
#expect(("00" as NSString).index(after: 0) == 1)
|
||||
#expect(("00" as NSString).index(after: 1) == 2)
|
||||
#expect(("00" as NSString).index(after: 2) == 2)
|
||||
#expect(("0🇦🇦0" as NSString).index(after: 0) == 1)
|
||||
#expect(("0🇦🇦0" as NSString).index(after: 1) == 5)
|
||||
|
||||
XCTAssertEqual(("0\r\n0" as NSString).index(after: 1), 3)
|
||||
XCTAssertEqual(("0\r\n0" as NSString).index(after: 2), 3)
|
||||
XCTAssertEqual(("0\r\n0" as NSString).index(after: 3), 4)
|
||||
XCTAssertEqual(("0\r" as NSString).index(after: 1), 2)
|
||||
XCTAssertEqual(("0\r" as NSString).index(after: 2), 2)
|
||||
#expect(("0\r\n0" as NSString).index(after: 1) == 3)
|
||||
#expect(("0\r\n0" as NSString).index(after: 2) == 3)
|
||||
#expect(("0\r\n0" as NSString).index(after: 3) == 4)
|
||||
#expect(("0\r" as NSString).index(after: 1) == 2)
|
||||
#expect(("0\r" as NSString).index(after: 2) == 2)
|
||||
|
||||
// composed character does not care CRLF
|
||||
XCTAssertEqual(("\r\n" as NSString).rangeOfComposedCharacterSequence(at: 1), NSRange(1..<2))
|
||||
#expect(("\r\n" as NSString).rangeOfComposedCharacterSequence(at: 1) == NSRange(1..<2))
|
||||
}
|
||||
|
||||
|
||||
func testLineRange() {
|
||||
@Test func lineRange() {
|
||||
|
||||
let string = "foo\n\rbar\n\r"
|
||||
|
||||
XCTAssertEqual(string.lineContentsRange(for: string.startIndex..<string.endIndex),
|
||||
string.startIndex..<string.index(before: string.endIndex))
|
||||
#expect(string.lineContentsRange(for: string.startIndex..<string.endIndex) ==
|
||||
string.startIndex..<string.index(before: string.endIndex))
|
||||
|
||||
XCTAssertEqual(string.lineRange(at: string.index(after: string.startIndex)),
|
||||
string.startIndex..<string.index(string.startIndex, offsetBy: 4))
|
||||
XCTAssertEqual(string.lineContentsRange(for: string.startIndex..<string.index(after: string.startIndex)),
|
||||
string.startIndex..<string.index(string.startIndex, offsetBy: 3))
|
||||
#expect(string.lineRange(at: string.index(after: string.startIndex)) ==
|
||||
string.startIndex..<string.index(string.startIndex, offsetBy: 4))
|
||||
#expect(string.lineContentsRange(for: string.startIndex..<string.index(after: string.startIndex)) ==
|
||||
string.startIndex..<string.index(string.startIndex, offsetBy: 3))
|
||||
|
||||
XCTAssertEqual((string as NSString).lineContentsRange(for: NSRange(..<1)), NSRange(..<3))
|
||||
XCTAssertEqual((string as NSString).lineContentsRange(at: 5), NSRange(5..<8))
|
||||
#expect((string as NSString).lineContentsRange(for: NSRange(..<1)) == NSRange(..<3))
|
||||
#expect((string as NSString).lineContentsRange(at: 5) == NSRange(5..<8))
|
||||
|
||||
let emptyString = ""
|
||||
let emptyRange = emptyString.startIndex..<emptyString.endIndex
|
||||
|
||||
XCTAssertEqual(emptyString.lineContentsRange(for: emptyRange), emptyRange)
|
||||
#expect(emptyString.lineContentsRange(for: emptyRange) == emptyRange)
|
||||
}
|
||||
|
||||
|
||||
func testLineRanges() {
|
||||
@Test func lineRanges() {
|
||||
|
||||
XCTAssertEqual("foo\nbar".lineContentsRanges(for: NSRange(1..<1)), [NSRange(1..<1)])
|
||||
XCTAssertEqual("foo\nbar".lineContentsRanges(), [NSRange(0..<3), NSRange(4..<7)])
|
||||
XCTAssertEqual("foo\nbar\n".lineContentsRanges(), [NSRange(0..<3), NSRange(4..<7)])
|
||||
XCTAssertEqual("foo\r\nbar".lineContentsRanges(), [NSRange(0..<3), NSRange(5..<8)])
|
||||
XCTAssertEqual("foo\r\r\rbar".lineContentsRanges().count, 4)
|
||||
#expect("foo\nbar".lineContentsRanges(for: NSRange(1..<1)) == [NSRange(1..<1)])
|
||||
#expect("foo\nbar".lineContentsRanges() == [NSRange(0..<3), NSRange(4..<7)])
|
||||
#expect("foo\nbar\n".lineContentsRanges() == [NSRange(0..<3), NSRange(4..<7)])
|
||||
#expect("foo\r\nbar".lineContentsRanges() == [NSRange(0..<3), NSRange(5..<8)])
|
||||
#expect("foo\r\r\rbar".lineContentsRanges().count == 4)
|
||||
}
|
||||
|
||||
|
||||
func testFirstLineEnding() {
|
||||
@Test func firstLineEnding() {
|
||||
|
||||
XCTAssertEqual("foo\r\nbar".firstLineEnding, "\r\n")
|
||||
#expect("foo\r\nbar".firstLineEnding == "\r\n")
|
||||
}
|
||||
|
||||
|
||||
func testRangeOfCharacter() {
|
||||
@Test func rangeOfCharacter() {
|
||||
|
||||
let set = CharacterSet(charactersIn: "._")
|
||||
let string = "abc.d🐕f_ghij" as NSString
|
||||
|
||||
XCTAssertEqual(string.substring(with: string.rangeOfCharacter(until: set, at: 0)), "abc")
|
||||
XCTAssertEqual(string.substring(with: string.rangeOfCharacter(until: set, at: 4)), "d🐕f")
|
||||
XCTAssertEqual(string.substring(with: string.rangeOfCharacter(until: set, at: string.length - 1)), "ghij")
|
||||
#expect(string.substring(with: string.rangeOfCharacter(until: set, at: 0)) == "abc")
|
||||
#expect(string.substring(with: string.rangeOfCharacter(until: set, at: 4)) == "d🐕f")
|
||||
#expect(string.substring(with: string.rangeOfCharacter(until: set, at: string.length - 1)) == "ghij")
|
||||
}
|
||||
|
||||
|
||||
func testComposedCharacterSequence() {
|
||||
@Test func composedCharacterSequence() {
|
||||
|
||||
let blackDog = "🐕⬛" // 4
|
||||
XCTAssertEqual(blackDog.lowerBoundOfComposedCharacterSequence(2, offsetBy: 1), 0)
|
||||
#expect(blackDog.lowerBoundOfComposedCharacterSequence(2, offsetBy: 1) == 0)
|
||||
|
||||
let abcDog = "🐕⬛abc" // 4 1 1 1
|
||||
XCTAssertEqual(abcDog.lowerBoundOfComposedCharacterSequence(6, offsetBy: 1), "🐕⬛a".utf16.count)
|
||||
XCTAssertEqual(abcDog.lowerBoundOfComposedCharacterSequence(5, offsetBy: 1), "🐕⬛".utf16.count)
|
||||
#expect(abcDog.lowerBoundOfComposedCharacterSequence(6, offsetBy: 1) == "🐕⬛a".utf16.count)
|
||||
#expect(abcDog.lowerBoundOfComposedCharacterSequence(5, offsetBy: 1) == "🐕⬛".utf16.count)
|
||||
|
||||
let dogDog = "🐕⬛🐕" // 4 2
|
||||
XCTAssertEqual(dogDog.lowerBoundOfComposedCharacterSequence(5, offsetBy: 1), 0)
|
||||
XCTAssertEqual(dogDog.lowerBoundOfComposedCharacterSequence(6, offsetBy: 1), "🐕⬛".utf16.count)
|
||||
XCTAssertEqual(dogDog.lowerBoundOfComposedCharacterSequence(6, offsetBy: 0), "🐕⬛🐕".utf16.count)
|
||||
#expect(dogDog.lowerBoundOfComposedCharacterSequence(5, offsetBy: 1) == 0)
|
||||
#expect(dogDog.lowerBoundOfComposedCharacterSequence(6, offsetBy: 1) == "🐕⬛".utf16.count)
|
||||
#expect(dogDog.lowerBoundOfComposedCharacterSequence(6, offsetBy: 0) == "🐕⬛🐕".utf16.count)
|
||||
|
||||
let string = "🐕🏴☠️🇯🇵🧑💻" // 2 5 4 5
|
||||
XCTAssertEqual(string.lowerBoundOfComposedCharacterSequence(9, offsetBy: 3), 0)
|
||||
XCTAssertEqual(string.lowerBoundOfComposedCharacterSequence(9, offsetBy: 2), 0)
|
||||
XCTAssertEqual(string.lowerBoundOfComposedCharacterSequence(9, offsetBy: 1), "🐕".utf16.count)
|
||||
XCTAssertEqual(string.lowerBoundOfComposedCharacterSequence(9, offsetBy: 0), "🐕🏴☠️".utf16.count)
|
||||
#expect(string.lowerBoundOfComposedCharacterSequence(9, offsetBy: 3) == 0)
|
||||
#expect(string.lowerBoundOfComposedCharacterSequence(9, offsetBy: 2) == 0)
|
||||
#expect(string.lowerBoundOfComposedCharacterSequence(9, offsetBy: 1) == "🐕".utf16.count)
|
||||
#expect(string.lowerBoundOfComposedCharacterSequence(9, offsetBy: 0) == "🐕🏴☠️".utf16.count)
|
||||
|
||||
let abc = "abc"
|
||||
XCTAssertEqual(abc.lowerBoundOfComposedCharacterSequence(1, offsetBy: 2), 0)
|
||||
XCTAssertEqual(abc.lowerBoundOfComposedCharacterSequence(1, offsetBy: 1), 0)
|
||||
XCTAssertEqual(abc.lowerBoundOfComposedCharacterSequence(1, offsetBy: 0), 1)
|
||||
#expect(abc.lowerBoundOfComposedCharacterSequence(1, offsetBy: 2) == 0)
|
||||
#expect(abc.lowerBoundOfComposedCharacterSequence(1, offsetBy: 1) == 0)
|
||||
#expect(abc.lowerBoundOfComposedCharacterSequence(1, offsetBy: 0) == 1)
|
||||
}
|
||||
|
||||
|
||||
func testUnicodeNormalization() {
|
||||
@Test func normalizeUnicode() {
|
||||
|
||||
XCTAssertEqual("É \t 神 ㍑ ABC".precomposedStringWithCompatibilityMappingWithCasefold, "é \t 神 リットル abc")
|
||||
XCTAssertEqual("\u{1f71} \u{03b1}\u{0301}".precomposedStringWithHFSPlusMapping, "\u{1f71} \u{03ac}")
|
||||
XCTAssertEqual("\u{1f71}".precomposedStringWithHFSPlusMapping, "\u{1f71}") // test single char
|
||||
XCTAssertEqual("\u{1f71}".decomposedStringWithHFSPlusMapping, "\u{03b1}\u{0301}")
|
||||
#expect("É \t 神 ㍑ ABC".precomposedStringWithCompatibilityMappingWithCasefold == "é \t 神 リットル abc")
|
||||
#expect("\u{1f71} \u{03b1}\u{0301}".precomposedStringWithHFSPlusMapping == "\u{1f71} \u{03ac}")
|
||||
#expect("\u{1f71}".precomposedStringWithHFSPlusMapping == "\u{1f71}") // test single char
|
||||
#expect("\u{1f71}".decomposedStringWithHFSPlusMapping == "\u{03b1}\u{0301}")
|
||||
}
|
||||
|
||||
|
||||
func testWhitespaceTrimming() throws {
|
||||
@Test func trimWhitespace() throws {
|
||||
|
||||
let string = """
|
||||
|
||||
@ -399,7 +398,7 @@ final class StringExtensionsTests: XCTestCase {
|
||||
white space ->
|
||||
abc
|
||||
"""
|
||||
XCTAssertEqual(trimmed, expectedTrimmed)
|
||||
#expect(trimmed == expectedTrimmed)
|
||||
|
||||
let trimmedIgnoringEmptyLines = try string.trim(ranges: string.rangesOfTrailingWhitespace(ignoresEmptyLines: true))
|
||||
let expectedTrimmedIgnoringEmptyLines = """
|
||||
@ -409,36 +408,36 @@ final class StringExtensionsTests: XCTestCase {
|
||||
white space ->
|
||||
abc
|
||||
"""
|
||||
XCTAssertEqual(trimmedIgnoringEmptyLines, expectedTrimmedIgnoringEmptyLines)
|
||||
#expect(trimmedIgnoringEmptyLines == expectedTrimmedIgnoringEmptyLines)
|
||||
}
|
||||
|
||||
|
||||
func testAbbreviatedMatch() throws {
|
||||
@Test func abbreviatedMatch() throws {
|
||||
|
||||
let string = "The fox jumps over the lazy dogcow."
|
||||
|
||||
XCTAssertNil(string.abbreviatedMatch(with: "quick"))
|
||||
#expect(string.abbreviatedMatch(with: "quick") == nil)
|
||||
|
||||
let dogcow = try XCTUnwrap(string.abbreviatedMatch(with: "dogcow"))
|
||||
XCTAssertEqual(dogcow.score, 6)
|
||||
XCTAssertEqual(dogcow.ranges.count, 6)
|
||||
XCTAssertEqual(dogcow.remaining, "")
|
||||
let dogcow = try #require(string.abbreviatedMatch(with: "dogcow"))
|
||||
#expect(dogcow.score == 6)
|
||||
#expect(dogcow.ranges.count == 6)
|
||||
#expect(dogcow.remaining.isEmpty)
|
||||
|
||||
let ow = try XCTUnwrap(string.abbreviatedMatch(with: "ow"))
|
||||
XCTAssertEqual(ow.score, 29)
|
||||
XCTAssertEqual(ow.ranges.count, 2)
|
||||
XCTAssertEqual(ow.remaining, "")
|
||||
let ow = try #require(string.abbreviatedMatch(with: "ow"))
|
||||
#expect(ow.score == 29)
|
||||
#expect(ow.ranges.count == 2)
|
||||
#expect(ow.remaining.isEmpty)
|
||||
|
||||
let lazyTanuki = try XCTUnwrap(string.abbreviatedMatch(with: "lazy tanuki"))
|
||||
XCTAssertEqual(lazyTanuki.score, 5)
|
||||
XCTAssertEqual(lazyTanuki.ranges.count, 5)
|
||||
XCTAssertEqual(lazyTanuki.remaining, "tanuki")
|
||||
let lazyTanuki = try #require(string.abbreviatedMatch(with: "lazy tanuki"))
|
||||
#expect(lazyTanuki.score == 5)
|
||||
#expect(lazyTanuki.ranges.count == 5)
|
||||
#expect(lazyTanuki.remaining == "tanuki")
|
||||
|
||||
XCTAssertNil(string.abbreviatedMatchedRanges(with: "lazy tanuki"))
|
||||
XCTAssertEqual(string.abbreviatedMatchedRanges(with: "lazy tanuki", incomplete: true)?.count, 5)
|
||||
#expect(string.abbreviatedMatchedRanges(with: "lazy tanuki") == nil)
|
||||
#expect(string.abbreviatedMatchedRanges(with: "lazy tanuki", incomplete: true)?.count == 5)
|
||||
|
||||
XCTAssertEqual(string.abbreviatedMatchedRanges(with: "lazy w")?.count, 6)
|
||||
XCTAssertEqual(string.abbreviatedMatchedRanges(with: "lazy w", incomplete: true)?.count, 6)
|
||||
#expect(string.abbreviatedMatchedRanges(with: "lazy w")?.count == 6)
|
||||
#expect(string.abbreviatedMatchedRanges(with: "lazy w", incomplete: true)?.count == 6)
|
||||
}
|
||||
}
|
||||
|
||||
@ -449,7 +448,7 @@ private extension String {
|
||||
func trim(ranges: [NSRange]) throws -> String {
|
||||
|
||||
try ranges.reversed()
|
||||
.map { try XCTUnwrap(Range($0, in: self)) }
|
||||
.map { try #require(Range($0, in: self)) }
|
||||
.reduce(self) { $0.replacingCharacters(in: $1, with: "") }
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2015-2023 1024jp
|
||||
// © 2015-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -24,71 +24,72 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class StringIndentationTests: XCTestCase {
|
||||
struct StringIndentationTests {
|
||||
|
||||
// MARK: Indentation Style Detection Tests
|
||||
|
||||
func testIndentStyleDetection() {
|
||||
@Test func detectIndentStyle() {
|
||||
|
||||
let string = "\t\tfoo\tbar"
|
||||
|
||||
XCTAssertNil(string.detectedIndentStyle)
|
||||
#expect(string.detectedIndentStyle == nil)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Indentation Style Standardization Tests
|
||||
|
||||
func testIndentStyleStandardizationToTab() {
|
||||
@Test func standardizeIndentStyleToTab() {
|
||||
|
||||
let string = " foo bar\n "
|
||||
|
||||
// spaces to tab
|
||||
XCTAssertEqual(string.standardizingIndent(to: .tab, tabWidth: 2), "\t\t foo bar\n\t")
|
||||
XCTAssertEqual(string.standardizingIndent(to: .space, tabWidth: 2), string)
|
||||
#expect(string.standardizingIndent(to: .tab, tabWidth: 2) == "\t\t foo bar\n\t")
|
||||
#expect(string.standardizingIndent(to: .space, tabWidth: 2) == string)
|
||||
}
|
||||
|
||||
|
||||
func testIndentStyleStandardizationToSpace() {
|
||||
@Test func standardizeIndentStyleToSpace() {
|
||||
|
||||
let string = "\t\tfoo\tbar"
|
||||
|
||||
XCTAssertEqual(string.standardizingIndent(to: .space, tabWidth: 2), " foo\tbar")
|
||||
XCTAssertEqual(string.standardizingIndent(to: .tab, tabWidth: 2), string)
|
||||
#expect(string.standardizingIndent(to: .space, tabWidth: 2) == " foo\tbar")
|
||||
#expect(string.standardizingIndent(to: .tab, tabWidth: 2) == string)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Other Tests
|
||||
|
||||
func testIndentLevelDetection() {
|
||||
@Test func detectIndentLevel() {
|
||||
|
||||
XCTAssertEqual(" foo".indentLevel(at: 0, tabWidth: 4), 1)
|
||||
XCTAssertEqual(" foo".indentLevel(at: 4, tabWidth: 2), 2)
|
||||
XCTAssertEqual("\tfoo".indentLevel(at: 4, tabWidth: 2), 1)
|
||||
#expect(" foo".indentLevel(at: 0, tabWidth: 4) == 1)
|
||||
#expect(" foo".indentLevel(at: 4, tabWidth: 2) == 2)
|
||||
#expect("\tfoo".indentLevel(at: 4, tabWidth: 2) == 1)
|
||||
|
||||
// tab-space mix
|
||||
XCTAssertEqual(" \t foo".indentLevel(at: 4, tabWidth: 2), 2)
|
||||
XCTAssertEqual(" \t foo".indentLevel(at: 4, tabWidth: 2), 3)
|
||||
#expect(" \t foo".indentLevel(at: 4, tabWidth: 2) == 2)
|
||||
#expect(" \t foo".indentLevel(at: 4, tabWidth: 2) == 3)
|
||||
|
||||
// multiline
|
||||
XCTAssertEqual(" foo\n bar".indentLevel(at: 10, tabWidth: 2), 1)
|
||||
#expect(" foo\n bar".indentLevel(at: 10, tabWidth: 2) == 1)
|
||||
}
|
||||
|
||||
|
||||
func testSoftTabDeletion() {
|
||||
@Test func deleteSoftTab() {
|
||||
|
||||
let string = " foo\n bar "
|
||||
|
||||
XCTAssertNil(string.rangeForSoftTabDeletion(in: NSRange(0..<0), tabWidth: 2))
|
||||
XCTAssertNil(string.rangeForSoftTabDeletion(in: NSRange(4..<5), tabWidth: 2))
|
||||
XCTAssertNil(string.rangeForSoftTabDeletion(in: NSRange(6..<6), tabWidth: 2))
|
||||
XCTAssertEqual(string.rangeForSoftTabDeletion(in: NSRange(5..<5), tabWidth: 2), NSRange(4..<5))
|
||||
XCTAssertEqual(string.rangeForSoftTabDeletion(in: NSRange(4..<4), tabWidth: 2), NSRange(2..<4))
|
||||
XCTAssertNil(string.rangeForSoftTabDeletion(in: NSRange(10..<10), tabWidth: 2))
|
||||
XCTAssertEqual(string.rangeForSoftTabDeletion(in: NSRange(11..<11), tabWidth: 2), NSRange(9..<11))
|
||||
XCTAssertNil(string.rangeForSoftTabDeletion(in: NSRange(16..<16), tabWidth: 2))
|
||||
#expect(string.rangeForSoftTabDeletion(in: NSRange(0..<0), tabWidth: 2) == nil)
|
||||
#expect(string.rangeForSoftTabDeletion(in: NSRange(4..<5), tabWidth: 2) == nil)
|
||||
#expect(string.rangeForSoftTabDeletion(in: NSRange(6..<6), tabWidth: 2) == nil)
|
||||
#expect(string.rangeForSoftTabDeletion(in: NSRange(5..<5), tabWidth: 2) == NSRange(4..<5))
|
||||
#expect(string.rangeForSoftTabDeletion(in: NSRange(4..<4), tabWidth: 2) == NSRange(2..<4))
|
||||
#expect(string.rangeForSoftTabDeletion(in: NSRange(10..<10), tabWidth: 2) == nil)
|
||||
#expect(string.rangeForSoftTabDeletion(in: NSRange(11..<11), tabWidth: 2) == NSRange(9..<11))
|
||||
#expect(string.rangeForSoftTabDeletion(in: NSRange(16..<16), tabWidth: 2) == nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2020-2022 1024jp
|
||||
// © 2020-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -23,12 +23,13 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class StringLineProcessingTests: XCTestCase {
|
||||
struct StringLineProcessingTests {
|
||||
|
||||
func testMoveLineUp() {
|
||||
@Test func moveLineUp() throws {
|
||||
|
||||
let string = """
|
||||
aa
|
||||
@ -37,29 +38,28 @@ final class StringLineProcessingTests: XCTestCase {
|
||||
d
|
||||
eee
|
||||
"""
|
||||
var info: String.EditingInfo?
|
||||
var info: String.EditingInfo
|
||||
|
||||
info = string.moveLineUp(in: [NSRange(4, 1)])
|
||||
XCTAssertEqual(info?.strings, ["bbbb\naa\n"])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(0, 8)])
|
||||
XCTAssertEqual(info?.selectedRanges, [NSRange(1, 1)])
|
||||
info = try #require(string.moveLineUp(in: [NSRange(4, 1)]))
|
||||
#expect(info.strings == ["bbbb\naa\n"])
|
||||
#expect(info.ranges == [NSRange(0, 8)])
|
||||
#expect(info.selectedRanges == [NSRange(1, 1)])
|
||||
|
||||
info = string.moveLineUp(in: [NSRange(4, 1), NSRange(6, 0)])
|
||||
XCTAssertEqual(info?.strings, ["bbbb\naa\n"])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(0, 8)])
|
||||
XCTAssertEqual(info?.selectedRanges, [NSRange(1, 1), NSRange(3, 0)])
|
||||
info = try #require(string.moveLineUp(in: [NSRange(4, 1), NSRange(6, 0)]))
|
||||
#expect(info.strings == ["bbbb\naa\n"])
|
||||
#expect(info.ranges == [NSRange(0, 8)])
|
||||
#expect(info.selectedRanges == [NSRange(1, 1), NSRange(3, 0)])
|
||||
|
||||
info = string.moveLineUp(in: [NSRange(4, 1), NSRange(9, 0), NSRange(15, 1)])
|
||||
XCTAssertEqual(info?.strings, ["bbbb\nccc\naa\neee\nd"])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(0, 17)])
|
||||
XCTAssertEqual(info?.selectedRanges, [NSRange(1, 1), NSRange(6, 0), NSRange(13, 1)])
|
||||
info = try #require(string.moveLineUp(in: [NSRange(4, 1), NSRange(9, 0), NSRange(15, 1)]))
|
||||
#expect(info.strings == ["bbbb\nccc\naa\neee\nd"])
|
||||
#expect(info.ranges == [NSRange(0, 17)])
|
||||
#expect(info.selectedRanges == [NSRange(1, 1), NSRange(6, 0), NSRange(13, 1)])
|
||||
|
||||
info = string.moveLineUp(in: [NSRange(2, 1)])
|
||||
XCTAssertNil(info)
|
||||
#expect(string.moveLineUp(in: [NSRange(2, 1)]) == nil)
|
||||
}
|
||||
|
||||
|
||||
func testMoveLineDown() {
|
||||
@Test func moveLineDown() throws {
|
||||
|
||||
let string = """
|
||||
aa
|
||||
@ -68,77 +68,74 @@ final class StringLineProcessingTests: XCTestCase {
|
||||
d
|
||||
eee
|
||||
"""
|
||||
var info: String.EditingInfo?
|
||||
var info: String.EditingInfo
|
||||
|
||||
info = string.moveLineDown(in: [NSRange(4, 1)])
|
||||
XCTAssertEqual(info?.strings, ["aa\nccc\nbbbb\n"])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(0, 12)])
|
||||
XCTAssertEqual(info?.selectedRanges, [NSRange(8, 1)])
|
||||
info = try #require(string.moveLineDown(in: [NSRange(4, 1)]))
|
||||
#expect(info.strings == ["aa\nccc\nbbbb\n"])
|
||||
#expect(info.ranges == [NSRange(0, 12)])
|
||||
#expect(info.selectedRanges == [NSRange(8, 1)])
|
||||
|
||||
info = string.moveLineDown(in: [NSRange(4, 1), NSRange(6, 0)])
|
||||
XCTAssertEqual(info?.strings, ["aa\nccc\nbbbb\n"])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(0, 12)])
|
||||
XCTAssertEqual(info?.selectedRanges, [NSRange(8, 1), NSRange(10, 0)])
|
||||
info = try #require(string.moveLineDown(in: [NSRange(4, 1), NSRange(6, 0)]))
|
||||
#expect(info.strings == ["aa\nccc\nbbbb\n"])
|
||||
#expect(info.ranges == [NSRange(0, 12)])
|
||||
#expect(info.selectedRanges == [NSRange(8, 1), NSRange(10, 0)])
|
||||
|
||||
info = string.moveLineDown(in: [NSRange(4, 1), NSRange(9, 0), NSRange(13, 1)])
|
||||
XCTAssertEqual(info?.strings, ["aa\neee\nbbbb\nccc\nd"])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(0, 17)])
|
||||
XCTAssertEqual(info?.selectedRanges, [NSRange(8, 1), NSRange(13, 0), NSRange(17, 1)])
|
||||
info = try #require(string.moveLineDown(in: [NSRange(4, 1), NSRange(9, 0), NSRange(13, 1)]))
|
||||
#expect(info.strings == ["aa\neee\nbbbb\nccc\nd"])
|
||||
#expect(info.ranges == [NSRange(0, 17)])
|
||||
#expect(info.selectedRanges == [NSRange(8, 1), NSRange(13, 0), NSRange(17, 1)])
|
||||
|
||||
info = string.moveLineDown(in: [NSRange(14, 1)])
|
||||
XCTAssertNil(info)
|
||||
#expect(string.moveLineDown(in: [NSRange(14, 1)]) == nil)
|
||||
}
|
||||
|
||||
|
||||
func testSortLinesAscending() {
|
||||
@Test func sortLinesAscending() throws {
|
||||
|
||||
let string = """
|
||||
ccc
|
||||
aa
|
||||
bbbb
|
||||
"""
|
||||
var info: String.EditingInfo?
|
||||
var info: String.EditingInfo
|
||||
|
||||
info = string.sortLinesAscending(in: NSRange(4, 1))
|
||||
XCTAssertNil(info)
|
||||
#expect(string.sortLinesAscending(in: NSRange(4, 1)) == nil)
|
||||
|
||||
info = string.sortLinesAscending(in: string.nsRange)
|
||||
XCTAssertEqual(info?.strings, ["aa\nbbbb\nccc"])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(0, 11)])
|
||||
XCTAssertEqual(info?.selectedRanges, [NSRange(0, 11)])
|
||||
info = try #require(string.sortLinesAscending(in: string.nsRange))
|
||||
#expect(info.strings == ["aa\nbbbb\nccc"])
|
||||
#expect(info.ranges == [NSRange(0, 11)])
|
||||
#expect(info.selectedRanges == [NSRange(0, 11)])
|
||||
|
||||
info = string.sortLinesAscending(in: NSRange(2, 4))
|
||||
XCTAssertEqual(info?.strings, ["aa\nccc"])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(0, 6)])
|
||||
XCTAssertEqual(info?.selectedRanges, [NSRange(0, 6)])
|
||||
info = try #require(string.sortLinesAscending(in: NSRange(2, 4)))
|
||||
#expect(info.strings == ["aa\nccc"])
|
||||
#expect(info.ranges == [NSRange(0, 6)])
|
||||
#expect(info.selectedRanges == [NSRange(0, 6)])
|
||||
}
|
||||
|
||||
|
||||
func testReverseLines() {
|
||||
@Test func reverseLines() throws {
|
||||
|
||||
let string = """
|
||||
aa
|
||||
bbbb
|
||||
ccc
|
||||
"""
|
||||
var info: String.EditingInfo?
|
||||
var info: String.EditingInfo
|
||||
|
||||
info = string.reverseLines(in: NSRange(4, 1))
|
||||
XCTAssertNil(info)
|
||||
#expect(string.reverseLines(in: NSRange(4, 1)) == nil)
|
||||
|
||||
info = string.reverseLines(in: string.nsRange)
|
||||
XCTAssertEqual(info?.strings, ["ccc\nbbbb\naa"])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(0, 11)])
|
||||
XCTAssertEqual(info?.selectedRanges, [NSRange(0, 11)])
|
||||
info = try #require(string.reverseLines(in: string.nsRange))
|
||||
#expect(info.strings == ["ccc\nbbbb\naa"])
|
||||
#expect(info.ranges == [NSRange(0, 11)])
|
||||
#expect(info.selectedRanges == [NSRange(0, 11)])
|
||||
|
||||
info = string.reverseLines(in: NSRange(2, 4))
|
||||
XCTAssertEqual(info?.strings, ["bbbb\naa"])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(0, 7)])
|
||||
XCTAssertEqual(info?.selectedRanges, [NSRange(0, 7)])
|
||||
info = try #require(string.reverseLines(in: NSRange(2, 4)))
|
||||
#expect(info.strings == ["bbbb\naa"])
|
||||
#expect(info.ranges == [NSRange(0, 7)])
|
||||
#expect(info.selectedRanges == [NSRange(0, 7)])
|
||||
}
|
||||
|
||||
|
||||
func testDeleteDuplicateLine() {
|
||||
@Test func deleteDuplicateLine() throws {
|
||||
|
||||
let string = """
|
||||
aa
|
||||
@ -147,76 +144,75 @@ final class StringLineProcessingTests: XCTestCase {
|
||||
ccc
|
||||
bbbb
|
||||
"""
|
||||
var info: String.EditingInfo?
|
||||
var info: String.EditingInfo
|
||||
|
||||
info = string.deleteDuplicateLine(in: [NSRange(4, 1)])
|
||||
XCTAssertNil(info)
|
||||
#expect(string.deleteDuplicateLine(in: [NSRange(4, 1)]) == nil)
|
||||
|
||||
info = string.deleteDuplicateLine(in: [string.nsRange])
|
||||
XCTAssertEqual(info?.strings, ["", ""])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(12, 4), NSRange(16, 4)])
|
||||
XCTAssertNil(info?.selectedRanges)
|
||||
info = try #require(string.deleteDuplicateLine(in: [string.nsRange]))
|
||||
#expect(info.strings == ["", ""])
|
||||
#expect(info.ranges == [NSRange(12, 4), NSRange(16, 4)])
|
||||
#expect(info.selectedRanges == nil)
|
||||
|
||||
info = string.deleteDuplicateLine(in: [NSRange(10, 4)])
|
||||
XCTAssertEqual(info?.strings, [""])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(12, 4)])
|
||||
XCTAssertNil(info?.selectedRanges)
|
||||
info = try #require(string.deleteDuplicateLine(in: [NSRange(10, 4)]))
|
||||
#expect(info.strings == [""])
|
||||
#expect(info.ranges == [NSRange(12, 4)])
|
||||
#expect(info.selectedRanges == nil)
|
||||
|
||||
info = string.deleteDuplicateLine(in: [NSRange(9, 1), NSRange(11, 0), NSRange(13, 2)])
|
||||
XCTAssertEqual(info?.strings, [""])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(12, 4)])
|
||||
XCTAssertNil(info?.selectedRanges)
|
||||
info = try #require(string.deleteDuplicateLine(in: [NSRange(9, 1), NSRange(11, 0), NSRange(13, 2)]))
|
||||
#expect(info.strings == [""])
|
||||
#expect(info.ranges == [NSRange(12, 4)])
|
||||
#expect(info.selectedRanges == nil)
|
||||
}
|
||||
|
||||
|
||||
func testDuplicateLine() {
|
||||
@Test func duplicateLine() throws {
|
||||
|
||||
let string = """
|
||||
aa
|
||||
bbbb
|
||||
ccc
|
||||
"""
|
||||
var info: String.EditingInfo?
|
||||
var info: String.EditingInfo
|
||||
|
||||
info = string.duplicateLine(in: [NSRange(4, 1)], lineEnding: "\n")
|
||||
XCTAssertEqual(info?.strings, ["bbbb\n"])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(3, 0)])
|
||||
XCTAssertEqual(info?.selectedRanges, [NSRange(9, 1)])
|
||||
info = try #require(string.duplicateLine(in: [NSRange(4, 1)], lineEnding: "\n"))
|
||||
#expect(info.strings == ["bbbb\n"])
|
||||
#expect(info.ranges == [NSRange(3, 0)])
|
||||
#expect(info.selectedRanges == [NSRange(9, 1)])
|
||||
|
||||
info = string.duplicateLine(in: [NSRange(4, 1), NSRange(6, 4)], lineEnding: "\n")
|
||||
XCTAssertEqual(info?.strings, ["bbbb\nccc\n"])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(3, 0)])
|
||||
XCTAssertEqual(info?.selectedRanges, [NSRange(13, 1), NSRange(15, 4)])
|
||||
info = try #require(string.duplicateLine(in: [NSRange(4, 1), NSRange(6, 4)], lineEnding: "\n"))
|
||||
#expect(info.strings == ["bbbb\nccc\n"])
|
||||
#expect(info.ranges == [NSRange(3, 0)])
|
||||
#expect(info.selectedRanges == [NSRange(13, 1), NSRange(15, 4)])
|
||||
|
||||
info = string.duplicateLine(in: [NSRange(4, 1), NSRange(6, 1), NSRange(10, 0)], lineEnding: "\n")
|
||||
XCTAssertEqual(info?.strings, ["bbbb\n", "ccc\n"])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(3, 0), NSRange(8, 0)])
|
||||
XCTAssertEqual(info?.selectedRanges, [NSRange(9, 1), NSRange(11, 1), NSRange(19, 0)])
|
||||
info = try #require(string.duplicateLine(in: [NSRange(4, 1), NSRange(6, 1), NSRange(10, 0)], lineEnding: "\n"))
|
||||
#expect(info.strings == ["bbbb\n", "ccc\n"])
|
||||
#expect(info.ranges == [NSRange(3, 0), NSRange(8, 0)])
|
||||
#expect(info.selectedRanges == [NSRange(9, 1), NSRange(11, 1), NSRange(19, 0)])
|
||||
}
|
||||
|
||||
|
||||
func testDeleteLine() {
|
||||
@Test func deleteLine() throws {
|
||||
|
||||
let string = """
|
||||
aa
|
||||
bbbb
|
||||
ccc
|
||||
"""
|
||||
var info: String.EditingInfo?
|
||||
var info: String.EditingInfo
|
||||
|
||||
info = string.deleteLine(in: [NSRange(4, 1)])
|
||||
XCTAssertEqual(info?.strings, [""])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(3, 5)])
|
||||
XCTAssertEqual(info?.selectedRanges, [NSRange(3, 0)])
|
||||
info = try #require(string.deleteLine(in: [NSRange(4, 1)]))
|
||||
#expect(info.strings == [""])
|
||||
#expect(info.ranges == [NSRange(3, 5)])
|
||||
#expect(info.selectedRanges == [NSRange(3, 0)])
|
||||
|
||||
info = string.deleteLine(in: [NSRange(4, 1), NSRange(6, 1), NSRange(10, 0)])
|
||||
XCTAssertEqual(info?.strings, ["", ""])
|
||||
XCTAssertEqual(info?.ranges, [NSRange(3, 5), NSRange(8, 3)])
|
||||
XCTAssertEqual(info?.selectedRanges, [NSRange(3, 0)])
|
||||
info = try #require(string.deleteLine(in: [NSRange(4, 1), NSRange(6, 1), NSRange(10, 0)]))
|
||||
#expect(info.strings == ["", ""])
|
||||
#expect(info.ranges == [NSRange(3, 5), NSRange(8, 3)])
|
||||
#expect(info.selectedRanges == [NSRange(3, 0)])
|
||||
}
|
||||
|
||||
|
||||
func testJoinLinesIn() {
|
||||
@Test func joinLinesIn() {
|
||||
|
||||
let string = """
|
||||
aa
|
||||
@ -226,13 +222,13 @@ final class StringLineProcessingTests: XCTestCase {
|
||||
"""
|
||||
let info = string.joinLines(in: [NSRange(1, 6), NSRange(10, 1)])
|
||||
|
||||
XCTAssertEqual(info.strings, ["a bb", "c"])
|
||||
XCTAssertEqual(info.ranges, [NSRange(1, 6), NSRange(10, 1)])
|
||||
XCTAssertEqual(info.selectedRanges, [NSRange(1, 4), NSRange(8, 1)])
|
||||
#expect(info.strings == ["a bb", "c"])
|
||||
#expect(info.ranges == [NSRange(1, 6), NSRange(10, 1)])
|
||||
#expect(info.selectedRanges == [NSRange(1, 4), NSRange(8, 1)])
|
||||
}
|
||||
|
||||
|
||||
func testJoinLinesAfter() {
|
||||
@Test func joinLinesAfter() {
|
||||
|
||||
let string = """
|
||||
aa
|
||||
@ -242,9 +238,9 @@ final class StringLineProcessingTests: XCTestCase {
|
||||
"""
|
||||
let info = string.joinLines(after: [NSRange(1, 0), NSRange(10, 0), NSRange(14, 0)])
|
||||
|
||||
XCTAssertEqual(info.strings, [" ", " "])
|
||||
XCTAssertEqual(info.ranges, [NSRange(2, 3), NSRange(13, 1)])
|
||||
XCTAssertNil(info.selectedRanges)
|
||||
#expect(info.strings == [" ", " "])
|
||||
#expect(info.ranges == [NSRange(2, 3), NSRange(13, 1)])
|
||||
#expect(info.selectedRanges == nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,12 +24,13 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import AppKit
|
||||
import Testing
|
||||
import Combine
|
||||
import Yams
|
||||
@testable import CotEditor
|
||||
|
||||
final class SyntaxTests: XCTestCase {
|
||||
final class SyntaxTests {
|
||||
|
||||
private let syntaxDirectoryName = "Syntaxes"
|
||||
|
||||
@ -41,12 +42,10 @@ final class SyntaxTests: XCTestCase {
|
||||
|
||||
|
||||
|
||||
override func setUpWithError() throws {
|
||||
|
||||
try super.setUpWithError()
|
||||
init() throws {
|
||||
|
||||
let bundle = Bundle(for: type(of: self))
|
||||
let urls = try XCTUnwrap(bundle.urls(forResourcesWithExtension: "yml", subdirectory: self.syntaxDirectoryName))
|
||||
let urls = try #require(bundle.urls(forResourcesWithExtension: "yml", subdirectory: self.syntaxDirectoryName))
|
||||
|
||||
// load syntaxes
|
||||
let decoder = YAMLDecoder()
|
||||
@ -56,129 +55,128 @@ final class SyntaxTests: XCTestCase {
|
||||
|
||||
dict[name] = try decoder.decode(Syntax.self, from: data)
|
||||
}
|
||||
self.htmlSyntax = try XCTUnwrap(self.syntaxes["HTML"])
|
||||
|
||||
XCTAssertNotNil(self.htmlSyntax)
|
||||
self.htmlSyntax = try #require(self.syntaxes["HTML"])
|
||||
|
||||
// load test file
|
||||
let sourceURL = try XCTUnwrap(bundle.url(forResource: "sample", withExtension: "html"))
|
||||
let sourceURL = try #require(bundle.url(forResource: "sample", withExtension: "html"))
|
||||
self.htmlSource = try String(contentsOf: sourceURL)
|
||||
|
||||
XCTAssertNotNil(self.htmlSource)
|
||||
}
|
||||
|
||||
|
||||
func testAllSyntaxes() {
|
||||
@Test func loadHTML() {
|
||||
|
||||
#expect(self.htmlSyntax != nil)
|
||||
#expect(self.htmlSource != nil)
|
||||
}
|
||||
|
||||
|
||||
@Test func allSyntaxes() {
|
||||
|
||||
for (name, syntax) in self.syntaxes {
|
||||
let model = SyntaxObject(value: syntax)
|
||||
let errors = model.validate()
|
||||
|
||||
XCTAssert(errors.isEmpty)
|
||||
#expect(errors.isEmpty)
|
||||
for error in errors {
|
||||
XCTFail("\(name): \(error)")
|
||||
Issue.record("\(name): \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testSanitization() {
|
||||
@Test func sanitize() {
|
||||
|
||||
for (name, syntax) in self.syntaxes {
|
||||
let sanitized = syntax.sanitized
|
||||
|
||||
XCTAssertEqual(syntax.kind, sanitized.kind)
|
||||
#expect(syntax.kind == sanitized.kind)
|
||||
|
||||
for type in SyntaxType.allCases {
|
||||
let keyPath = Syntax.highlightKeyPath(for: type)
|
||||
XCTAssertEqual(syntax[keyPath: keyPath], sanitized[keyPath: keyPath],
|
||||
".\(type.rawValue) of “\(name)” is not sanitized in the latest manner")
|
||||
#expect(syntax[keyPath: keyPath] == sanitized[keyPath: keyPath],
|
||||
".\(type.rawValue) of “\(name)” is not sanitized in the latest manner")
|
||||
}
|
||||
|
||||
XCTAssertEqual(syntax.outlines, sanitized.outlines,
|
||||
".outlines of “\(name)” is not sanitized in the latest manner")
|
||||
XCTAssertEqual(syntax.completions, sanitized.completions,
|
||||
".completions of “\(name)” is not sanitized in the latest manner")
|
||||
XCTAssertEqual(syntax.commentDelimiters, sanitized.commentDelimiters,
|
||||
".commentDelimiters of “\(name)” is not sanitized in the latest manner")
|
||||
XCTAssertEqual(syntax.extensions, sanitized.extensions,
|
||||
".extensions of “\(name)” is not sanitized in the latest manner")
|
||||
XCTAssertEqual(syntax.filenames, sanitized.filenames,
|
||||
".filenames of “\(name)” is not sanitized in the latest manner")
|
||||
XCTAssertEqual(syntax.interpreters, sanitized.interpreters,
|
||||
".interpreters of “\(name)” is not sanitized in the latest manner")
|
||||
XCTAssertEqual(syntax.metadata, sanitized.metadata,
|
||||
".metadata of “\(name)” is not sanitized in the latest manner")
|
||||
#expect(syntax.outlines == sanitized.outlines,
|
||||
".outlines of “\(name)” is not sanitized in the latest manner")
|
||||
#expect(syntax.completions == sanitized.completions,
|
||||
".completions of “\(name)” is not sanitized in the latest manner")
|
||||
#expect(syntax.commentDelimiters == sanitized.commentDelimiters,
|
||||
".commentDelimiters of “\(name)” is not sanitized in the latest manner")
|
||||
#expect(syntax.extensions == sanitized.extensions,
|
||||
".extensions of “\(name)” is not sanitized in the latest manner")
|
||||
#expect(syntax.filenames == sanitized.filenames,
|
||||
".filenames of “\(name)” is not sanitized in the latest manner")
|
||||
#expect(syntax.interpreters == sanitized.interpreters,
|
||||
".interpreters of “\(name)” is not sanitized in the latest manner")
|
||||
#expect(syntax.metadata == sanitized.metadata,
|
||||
".metadata of “\(name)” is not sanitized in the latest manner")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testEquality() {
|
||||
|
||||
XCTAssertEqual(self.htmlSyntax, self.htmlSyntax)
|
||||
}
|
||||
|
||||
|
||||
func testNoneSyntax() {
|
||||
@Test func noneSyntax() {
|
||||
|
||||
let syntax = Syntax.none
|
||||
|
||||
XCTAssertEqual(syntax.kind, .code)
|
||||
XCTAssert(syntax.highlightParser.isEmpty)
|
||||
XCTAssertNil(syntax.commentDelimiters.inline)
|
||||
XCTAssertNil(syntax.commentDelimiters.block)
|
||||
#expect(syntax.kind == .code)
|
||||
#expect(syntax.highlightParser.isEmpty)
|
||||
#expect(syntax.commentDelimiters.inline == nil)
|
||||
#expect(syntax.commentDelimiters.block == nil)
|
||||
}
|
||||
|
||||
|
||||
func testXMLSyntax() throws {
|
||||
@Test func xmlSyntax() throws {
|
||||
|
||||
let syntax = try XCTUnwrap(self.htmlSyntax)
|
||||
let syntax = try #require(self.htmlSyntax)
|
||||
|
||||
XCTAssertFalse(syntax.highlightParser.isEmpty)
|
||||
XCTAssertNil(syntax.commentDelimiters.inline)
|
||||
XCTAssertEqual(syntax.commentDelimiters.block, Pair("<!--", "-->"))
|
||||
#expect(!syntax.highlightParser.isEmpty)
|
||||
#expect(syntax.commentDelimiters.inline == nil)
|
||||
#expect(syntax.commentDelimiters.block == Pair("<!--", "-->"))
|
||||
}
|
||||
|
||||
|
||||
func testOutlineParse() throws {
|
||||
@Test func parseOutline() async throws {
|
||||
|
||||
let syntax = try XCTUnwrap(self.htmlSyntax)
|
||||
let source = try XCTUnwrap(self.htmlSource)
|
||||
let syntax = try #require(self.htmlSyntax)
|
||||
let source = try #require(self.htmlSource)
|
||||
|
||||
let textStorage = NSTextStorage(string: source)
|
||||
let parser = SyntaxParser(textStorage: textStorage, syntax: syntax, name: "HTML")
|
||||
|
||||
// test outline parsing with publisher
|
||||
let outlineParseExpectation = self.expectation(description: "didParseOutline")
|
||||
self.outlineParseCancellable = parser.$outlineItems
|
||||
.compactMap { $0 } // ignore the initial invocation
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { outlineItems in
|
||||
outlineParseExpectation.fulfill()
|
||||
|
||||
XCTAssertEqual(outlineItems.count, 3)
|
||||
|
||||
XCTAssertEqual(parser.outlineItems, outlineItems)
|
||||
|
||||
let item = outlineItems[1]
|
||||
XCTAssertEqual(item.title, " h2: 🐕🐄")
|
||||
XCTAssertEqual(item.range.location, 354)
|
||||
XCTAssertEqual(item.range.length, 13)
|
||||
XCTAssertTrue(item.style.isEmpty)
|
||||
}
|
||||
parser.invalidateOutline()
|
||||
self.waitForExpectations(timeout: 1)
|
||||
try await confirmation("didParseOutline") { confirm in
|
||||
self.outlineParseCancellable = parser.$outlineItems
|
||||
.compactMap { $0 } // ignore the initial invocation
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { outlineItems in
|
||||
confirm()
|
||||
|
||||
#expect(outlineItems.count == 3)
|
||||
|
||||
#expect(parser.outlineItems == outlineItems)
|
||||
|
||||
let item = outlineItems[1]
|
||||
#expect(item.title == " h2: 🐕🐄")
|
||||
#expect(item.range.location == 354)
|
||||
#expect(item.range.length == 13)
|
||||
#expect(item.style.isEmpty)
|
||||
}
|
||||
|
||||
parser.invalidateOutline()
|
||||
try await Task.sleep(for: .seconds(0.5))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testViewModelHighlightEquality() {
|
||||
@Test func viewModelHighlightEquality() {
|
||||
|
||||
let termA = SyntaxObject.Highlight(begin: "abc", end: "def")
|
||||
let termB = SyntaxObject.Highlight(begin: "abc", end: "def")
|
||||
let termC = SyntaxObject.Highlight(begin: "abc")
|
||||
|
||||
XCTAssertEqual(termA, termB)
|
||||
XCTAssertNotEqual(termA, termC)
|
||||
XCTAssertNotEqual(termA.id, termB.id)
|
||||
#expect(termA == termB)
|
||||
#expect(termA != termC)
|
||||
#expect(termA.id != termB.id)
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2020-2023 1024jp
|
||||
// © 2020-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -23,17 +23,18 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class TextClippingTests: XCTestCase {
|
||||
actor TextClippingTests {
|
||||
|
||||
func testReadingTextClippingFile() throws {
|
||||
@Test func readTextClippingFile() throws {
|
||||
|
||||
let bundle = Bundle(for: type(of: self))
|
||||
let url = try XCTUnwrap(bundle.url(forResource: "moof", withExtension: "textClipping"))
|
||||
let url = try #require(bundle.url(forResource: "moof", withExtension: "textClipping"))
|
||||
let textClipping = try TextClipping(contentsOf: url)
|
||||
|
||||
XCTAssertEqual(textClipping.string, "🐕moof🐄")
|
||||
#expect(textClipping.string == "🐕moof🐄")
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2017-2023 1024jp
|
||||
// © 2017-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -24,45 +24,32 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import AppKit
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class TextFindTests: XCTestCase {
|
||||
struct TextFindTests {
|
||||
|
||||
func testTextFinderActions() {
|
||||
@Test func finderActions() {
|
||||
|
||||
XCTAssertEqual(TextFinder.Action.showFindInterface.rawValue,
|
||||
NSTextFinder.Action.showFindInterface.rawValue)
|
||||
XCTAssertEqual(TextFinder.Action.nextMatch.rawValue,
|
||||
NSTextFinder.Action.nextMatch.rawValue)
|
||||
XCTAssertEqual(TextFinder.Action.previousMatch.rawValue,
|
||||
NSTextFinder.Action.previousMatch.rawValue)
|
||||
XCTAssertEqual(TextFinder.Action.replaceAll.rawValue,
|
||||
NSTextFinder.Action.replaceAll.rawValue)
|
||||
XCTAssertEqual(TextFinder.Action.replace.rawValue,
|
||||
NSTextFinder.Action.replace.rawValue)
|
||||
XCTAssertEqual(TextFinder.Action.replaceAndFind.rawValue,
|
||||
NSTextFinder.Action.replaceAndFind.rawValue)
|
||||
XCTAssertEqual(TextFinder.Action.setSearchString.rawValue,
|
||||
NSTextFinder.Action.setSearchString.rawValue)
|
||||
XCTAssertEqual(TextFinder.Action.replaceAllInSelection.rawValue,
|
||||
NSTextFinder.Action.replaceAllInSelection.rawValue)
|
||||
XCTAssertEqual(TextFinder.Action.selectAll.rawValue,
|
||||
NSTextFinder.Action.selectAll.rawValue)
|
||||
XCTAssertEqual(TextFinder.Action.selectAllInSelection.rawValue,
|
||||
NSTextFinder.Action.selectAllInSelection.rawValue)
|
||||
XCTAssertEqual(TextFinder.Action.hideFindInterface.rawValue,
|
||||
NSTextFinder.Action.hideFindInterface.rawValue)
|
||||
XCTAssertEqual(TextFinder.Action.showReplaceInterface.rawValue,
|
||||
NSTextFinder.Action.showReplaceInterface.rawValue)
|
||||
XCTAssertEqual(TextFinder.Action.showReplaceInterface.rawValue,
|
||||
NSTextFinder.Action.showReplaceInterface.rawValue)
|
||||
XCTAssertEqual(TextFinder.Action.hideReplaceInterface.rawValue,
|
||||
NSTextFinder.Action.hideReplaceInterface.rawValue)
|
||||
#expect(TextFinder.Action.showFindInterface.rawValue == NSTextFinder.Action.showFindInterface.rawValue)
|
||||
#expect(TextFinder.Action.nextMatch.rawValue == NSTextFinder.Action.nextMatch.rawValue)
|
||||
#expect(TextFinder.Action.previousMatch.rawValue == NSTextFinder.Action.previousMatch.rawValue)
|
||||
#expect(TextFinder.Action.replaceAll.rawValue == NSTextFinder.Action.replaceAll.rawValue)
|
||||
#expect(TextFinder.Action.replace.rawValue == NSTextFinder.Action.replace.rawValue)
|
||||
#expect(TextFinder.Action.replaceAndFind.rawValue == NSTextFinder.Action.replaceAndFind.rawValue)
|
||||
#expect(TextFinder.Action.setSearchString.rawValue == NSTextFinder.Action.setSearchString.rawValue)
|
||||
#expect(TextFinder.Action.replaceAllInSelection.rawValue == NSTextFinder.Action.replaceAllInSelection.rawValue)
|
||||
#expect(TextFinder.Action.selectAll.rawValue == NSTextFinder.Action.selectAll.rawValue)
|
||||
#expect(TextFinder.Action.selectAllInSelection.rawValue == NSTextFinder.Action.selectAllInSelection.rawValue)
|
||||
#expect(TextFinder.Action.hideFindInterface.rawValue == NSTextFinder.Action.hideFindInterface.rawValue)
|
||||
#expect(TextFinder.Action.showReplaceInterface.rawValue == NSTextFinder.Action.showReplaceInterface.rawValue)
|
||||
#expect(TextFinder.Action.showReplaceInterface.rawValue == NSTextFinder.Action.showReplaceInterface.rawValue)
|
||||
#expect(TextFinder.Action.hideReplaceInterface.rawValue == NSTextFinder.Action.hideReplaceInterface.rawValue)
|
||||
}
|
||||
|
||||
|
||||
func testCaptureGroupCount() throws {
|
||||
@Test func countCaptureGroup() throws {
|
||||
|
||||
var mode: TextFind.Mode
|
||||
var textFind: TextFind
|
||||
@ -70,18 +57,18 @@ final class TextFindTests: XCTestCase {
|
||||
mode = .regularExpression(options: [], unescapesReplacement: false)
|
||||
|
||||
textFind = try TextFind(for: "", findString: "a", mode: mode)
|
||||
XCTAssertEqual(textFind.numberOfCaptureGroups, 0)
|
||||
#expect(textFind.numberOfCaptureGroups == 0)
|
||||
|
||||
textFind = try TextFind(for: "", findString: "(?!=a)(b)(c)(?=d)", mode: mode)
|
||||
XCTAssertEqual(textFind.numberOfCaptureGroups, 2)
|
||||
#expect(textFind.numberOfCaptureGroups == 2)
|
||||
|
||||
mode = .textual(options: [], fullWord: false)
|
||||
textFind = try TextFind(for: "", findString: "(?!=a)(b)(c)(?=d)", mode: mode)
|
||||
XCTAssertEqual(textFind.numberOfCaptureGroups, 0)
|
||||
#expect(textFind.numberOfCaptureGroups == 0)
|
||||
}
|
||||
|
||||
|
||||
func testSingleFind() throws {
|
||||
@Test func singleFind() throws {
|
||||
|
||||
let text = "abcdefg abcdefg ABCDEFG"
|
||||
let findString = "abc"
|
||||
@ -93,40 +80,40 @@ final class TextFindTests: XCTestCase {
|
||||
textFind = try TextFind(for: text, findString: findString, mode: .textual(options: [], fullWord: false))
|
||||
matches = try textFind.matches
|
||||
|
||||
result = try XCTUnwrap(textFind.find(in: matches, forward: true, wraps: false))
|
||||
XCTAssertEqual(matches.count, 2)
|
||||
XCTAssertEqual(result.range, NSRange(location: 0, length: 3))
|
||||
XCTAssertFalse(result.wrapped)
|
||||
result = try #require(textFind.find(in: matches, forward: true, wraps: false))
|
||||
#expect(matches.count == 2)
|
||||
#expect(result.range == NSRange(location: 0, length: 3))
|
||||
#expect(!result.wrapped)
|
||||
|
||||
XCTAssertNil(textFind.find(in: matches, forward: false, wraps: false))
|
||||
#expect(textFind.find(in: matches, forward: false, wraps: false) == nil)
|
||||
|
||||
|
||||
textFind = try TextFind(for: text, findString: findString, mode: .textual(options: [], fullWord: false), selectedRanges: [NSRange(location: 1, length: 0)])
|
||||
|
||||
matches = try textFind.matches
|
||||
XCTAssertEqual(matches.count, 2)
|
||||
#expect(matches.count == 2)
|
||||
|
||||
result = try XCTUnwrap(textFind.find(in: matches, forward: true, wraps: true))
|
||||
XCTAssertEqual(result.range, NSRange(location: 8, length: 3))
|
||||
XCTAssertFalse(result.wrapped)
|
||||
result = try #require(textFind.find(in: matches, forward: true, wraps: true))
|
||||
#expect(result.range == NSRange(location: 8, length: 3))
|
||||
#expect(!result.wrapped)
|
||||
|
||||
result = try XCTUnwrap(textFind.find(in: matches, forward: false, wraps: true))
|
||||
XCTAssertEqual(result.range, NSRange(location: 8, length: 3))
|
||||
XCTAssertTrue(result.wrapped)
|
||||
result = try #require(textFind.find(in: matches, forward: false, wraps: true))
|
||||
#expect(result.range == NSRange(location: 8, length: 3))
|
||||
#expect(result.wrapped)
|
||||
|
||||
|
||||
textFind = try TextFind(for: text, findString: findString, mode: .textual(options: .caseInsensitive, fullWord: false), selectedRanges: [NSRange(location: 1, length: 0)])
|
||||
|
||||
matches = try textFind.matches
|
||||
XCTAssertEqual(matches.count, 3)
|
||||
#expect(matches.count == 3)
|
||||
|
||||
result = try XCTUnwrap(textFind.find(in: matches, forward: false, wraps: true))
|
||||
XCTAssertEqual(result.range, NSRange(location: 16, length: 3))
|
||||
XCTAssertTrue(result.wrapped)
|
||||
result = try #require(textFind.find(in: matches, forward: false, wraps: true))
|
||||
#expect(result.range == NSRange(location: 16, length: 3))
|
||||
#expect(result.wrapped)
|
||||
}
|
||||
|
||||
|
||||
func testFullWord() throws {
|
||||
@Test func fullWord() throws {
|
||||
|
||||
var textFind: TextFind
|
||||
var result: (range: NSRange, wrapped: Bool)
|
||||
@ -135,43 +122,43 @@ final class TextFindTests: XCTestCase {
|
||||
textFind = try TextFind(for: "apples apple Apple", findString: "apple",
|
||||
mode: .textual(options: .caseInsensitive, fullWord: true))
|
||||
matches = try textFind.matches
|
||||
result = try XCTUnwrap(textFind.find(in: matches, forward: true, wraps: true))
|
||||
XCTAssertEqual(matches.count, 2)
|
||||
XCTAssertEqual(result.range, NSRange(location: 7, length: 5))
|
||||
result = try #require(textFind.find(in: matches, forward: true, wraps: true))
|
||||
#expect(matches.count == 2)
|
||||
#expect(result.range == NSRange(location: 7, length: 5))
|
||||
|
||||
textFind = try TextFind(for: "apples apple Apple", findString: "apple",
|
||||
mode: .textual(options: [.caseInsensitive, .literal], fullWord: true))
|
||||
matches = try textFind.matches
|
||||
result = try XCTUnwrap(textFind.find(in: matches, forward: true, wraps: true))
|
||||
XCTAssertEqual(matches.count, 2)
|
||||
XCTAssertEqual(result.range, NSRange(location: 7, length: 5))
|
||||
result = try #require(textFind.find(in: matches, forward: true, wraps: true))
|
||||
#expect(matches.count == 2)
|
||||
#expect(result.range == NSRange(location: 7, length: 5))
|
||||
|
||||
textFind = try TextFind(for: "Apfel Äpfel Äpfelchen", findString: "Äpfel",
|
||||
mode: .textual(options: .diacriticInsensitive, fullWord: true))
|
||||
matches = try textFind.matches
|
||||
result = try XCTUnwrap(textFind.find(in: matches, forward: true, wraps: true))
|
||||
XCTAssertEqual(matches.count, 2)
|
||||
XCTAssertEqual(result.range, NSRange(location: 0, length: 5))
|
||||
result = try #require(textFind.find(in: matches, forward: true, wraps: true))
|
||||
#expect(matches.count == 2)
|
||||
#expect(result.range == NSRange(location: 0, length: 5))
|
||||
|
||||
textFind = try TextFind(for: "イヌら イヌ イヌ", findString: "イヌ",
|
||||
mode: .textual(options: .widthInsensitive, fullWord: true))
|
||||
matches = try textFind.matches
|
||||
result = try XCTUnwrap(textFind.find(in: matches, forward: true, wraps: true))
|
||||
XCTAssertEqual(matches.count, 2)
|
||||
XCTAssertEqual(result.range, NSRange(location: 4, length: 2))
|
||||
result = try #require(textFind.find(in: matches, forward: true, wraps: true))
|
||||
#expect(matches.count == 2)
|
||||
#expect(result.range == NSRange(location: 4, length: 2))
|
||||
}
|
||||
|
||||
|
||||
func testUnescapedRegexFind() throws {
|
||||
@Test func unescapedRegexFind() throws {
|
||||
|
||||
let mode: TextFind.Mode = .regularExpression(options: .caseInsensitive, unescapesReplacement: true)
|
||||
let textFind = try TextFind(for: "1", findString: "1", mode: mode, selectedRanges: [NSRange(0..<1)])
|
||||
let replacementResult = try XCTUnwrap(textFind.replace(with: #"foo:\n1"#))
|
||||
XCTAssertEqual(replacementResult.value, "foo:\n1")
|
||||
let replacementResult = try #require(textFind.replace(with: #"foo:\n1"#))
|
||||
#expect(replacementResult.value == "foo:\n1")
|
||||
}
|
||||
|
||||
|
||||
func testSingleRegexFindAndReplacement() throws {
|
||||
@Test func findAndReplaceSingleRegex() throws {
|
||||
|
||||
let findString = "(?!=a)b(c)(?=d)"
|
||||
let mode: TextFind.Mode = .regularExpression(options: .caseInsensitive, unescapesReplacement: true)
|
||||
@ -184,42 +171,42 @@ final class TextFindTests: XCTestCase {
|
||||
textFind = try TextFind(for: "abcdefg abcdefg ABCDEFG", findString: findString, mode: mode, selectedRanges: [NSRange(location: 1, length: 1)])
|
||||
|
||||
matches = try textFind.matches
|
||||
XCTAssertEqual(matches.count, 3)
|
||||
#expect(matches.count == 3)
|
||||
|
||||
result = try XCTUnwrap(textFind.find(in: matches, forward: true, wraps: true))
|
||||
XCTAssertEqual(result.range, NSRange(location: 9, length: 2))
|
||||
XCTAssertFalse(result.wrapped)
|
||||
result = try #require(textFind.find(in: matches, forward: true, wraps: true))
|
||||
#expect(result.range == NSRange(location: 9, length: 2))
|
||||
#expect(!result.wrapped)
|
||||
|
||||
result = try XCTUnwrap(textFind.find(in: matches, forward: false, wraps: true))
|
||||
XCTAssertEqual(result.range, NSRange(location: 17, length: 2))
|
||||
XCTAssertTrue(result.wrapped)
|
||||
result = try #require(textFind.find(in: matches, forward: false, wraps: true))
|
||||
#expect(result.range == NSRange(location: 17, length: 2))
|
||||
#expect(result.wrapped)
|
||||
|
||||
|
||||
textFind = try TextFind(for: "ABCDEFG", findString: findString, mode: mode, selectedRanges: [NSRange(location: 1, length: 1)])
|
||||
|
||||
matches = try textFind.matches
|
||||
XCTAssertEqual(matches.count, 1)
|
||||
#expect(matches.count == 1)
|
||||
|
||||
result = try XCTUnwrap(textFind.find(in: matches, forward: true, wraps: true))
|
||||
XCTAssertEqual(result.range, NSRange(location: 1, length: 2))
|
||||
XCTAssertTrue(result.wrapped)
|
||||
result = try #require(textFind.find(in: matches, forward: true, wraps: true))
|
||||
#expect(result.range == NSRange(location: 1, length: 2))
|
||||
#expect(result.wrapped)
|
||||
|
||||
result = try XCTUnwrap(textFind.find(in: matches, forward: false, wraps: true))
|
||||
XCTAssertEqual(result.range, NSRange(location: 1, length: 2))
|
||||
XCTAssertTrue(result.wrapped)
|
||||
result = try #require(textFind.find(in: matches, forward: false, wraps: true))
|
||||
#expect(result.range == NSRange(location: 1, length: 2))
|
||||
#expect(result.wrapped)
|
||||
|
||||
XCTAssertNil(textFind.replace(with: "$1"))
|
||||
#expect(textFind.replace(with: "$1") == nil)
|
||||
|
||||
|
||||
textFind = try TextFind(for: "ABCDEFG", findString: findString, mode: mode, selectedRanges: [NSRange(location: 1, length: 2)])
|
||||
|
||||
let replacementResult = try XCTUnwrap(textFind.replace(with: "$1\\t"))
|
||||
XCTAssertEqual(replacementResult.value, "C\t")
|
||||
XCTAssertEqual(replacementResult.range, NSRange(location: 1, length: 2))
|
||||
let replacementResult = try #require(textFind.replace(with: "$1\\t"))
|
||||
#expect(replacementResult.value == "C\t")
|
||||
#expect(replacementResult.range == NSRange(location: 1, length: 2))
|
||||
}
|
||||
|
||||
|
||||
func testFindAll() throws {
|
||||
@Test func findAll() throws {
|
||||
|
||||
let mode: TextFind.Mode = .regularExpression(options: .caseInsensitive, unescapesReplacement: false)
|
||||
var textFind: TextFind
|
||||
@ -230,13 +217,13 @@ final class TextFindTests: XCTestCase {
|
||||
textFind.findAll { (matchedRanges, _) in
|
||||
matches.append(matchedRanges)
|
||||
}
|
||||
XCTAssertEqual(matches.count, 2)
|
||||
XCTAssertEqual(matches[0].count, 2)
|
||||
XCTAssertEqual(matches[0][0], NSRange(location: 1, length: 2))
|
||||
XCTAssertEqual(matches[0][1], NSRange(location: 2, length: 1))
|
||||
XCTAssertEqual(matches[1].count, 2)
|
||||
XCTAssertEqual(matches[1][0], NSRange(location: 9, length: 2))
|
||||
XCTAssertEqual(matches[1][1], NSRange(location: 10, length: 1))
|
||||
#expect(matches.count == 2)
|
||||
#expect(matches[0].count == 2)
|
||||
#expect(matches[0][0] == NSRange(location: 1, length: 2))
|
||||
#expect(matches[0][1] == NSRange(location: 2, length: 1))
|
||||
#expect(matches[1].count == 2)
|
||||
#expect(matches[1][0] == NSRange(location: 9, length: 2))
|
||||
#expect(matches[1][1] == NSRange(location: 10, length: 1))
|
||||
|
||||
|
||||
textFind = try TextFind(for: "abcdefg ABCDEFG", findString: "ab", mode: mode)
|
||||
@ -245,15 +232,15 @@ final class TextFindTests: XCTestCase {
|
||||
textFind.findAll { (matchedRanges, _) in
|
||||
matches.append(matchedRanges)
|
||||
}
|
||||
XCTAssertEqual(matches.count, 2)
|
||||
XCTAssertEqual(matches[0].count, 1)
|
||||
XCTAssertEqual(matches[0][0], NSRange(location: 0, length: 2))
|
||||
XCTAssertEqual(matches[1].count, 1)
|
||||
XCTAssertEqual(matches[1][0], NSRange(location: 8, length: 2))
|
||||
#expect(matches.count == 2)
|
||||
#expect(matches[0].count == 1)
|
||||
#expect(matches[0][0] == NSRange(location: 0, length: 2))
|
||||
#expect(matches[1].count == 1)
|
||||
#expect(matches[1][0] == NSRange(location: 8, length: 2))
|
||||
}
|
||||
|
||||
|
||||
func testReplaceAll() throws {
|
||||
@Test func replaceAll() throws {
|
||||
|
||||
var textFind: TextFind
|
||||
var replacementItems: [TextFind.ReplacementItem]
|
||||
@ -263,10 +250,10 @@ final class TextFindTests: XCTestCase {
|
||||
mode: .regularExpression(options: .caseInsensitive, unescapesReplacement: false))
|
||||
|
||||
(replacementItems, selectedRanges) = textFind.replaceAll(with: "$1\\\\t") { (_, _, _) in }
|
||||
XCTAssertEqual(replacementItems.count, 1)
|
||||
XCTAssertEqual(replacementItems[0].value, "ac\\tdefg AC\\tDEFG")
|
||||
XCTAssertEqual(replacementItems[0].range, NSRange(location: 0, length: 15))
|
||||
XCTAssertNil(selectedRanges)
|
||||
#expect(replacementItems.count == 1)
|
||||
#expect(replacementItems[0].value == "ac\\tdefg AC\\tDEFG")
|
||||
#expect(replacementItems[0].range == NSRange(location: 0, length: 15))
|
||||
#expect(selectedRanges == nil)
|
||||
|
||||
|
||||
textFind = try TextFind(for: "abcdefg abcdefg abcdefg", findString: "abc",
|
||||
@ -276,12 +263,12 @@ final class TextFindTests: XCTestCase {
|
||||
NSRange(location: 16, length: 7)])
|
||||
|
||||
(replacementItems, selectedRanges) = textFind.replaceAll(with: "_") { (_, _, _) in }
|
||||
XCTAssertEqual(replacementItems.count, 2)
|
||||
XCTAssertEqual(replacementItems[0].value, "bcdefg _defg")
|
||||
XCTAssertEqual(replacementItems[0].range, NSRange(location: 1, length: 14))
|
||||
XCTAssertEqual(replacementItems[1].value, "_defg")
|
||||
XCTAssertEqual(replacementItems[1].range, NSRange(location: 16, length: 7))
|
||||
XCTAssertEqual(selectedRanges?[0], NSRange(location: 1, length: 12))
|
||||
XCTAssertEqual(selectedRanges?[1], NSRange(location: 14, length: 5))
|
||||
#expect(replacementItems.count == 2)
|
||||
#expect(replacementItems[0].value == "bcdefg _defg")
|
||||
#expect(replacementItems[0].range == NSRange(location: 1, length: 14))
|
||||
#expect(replacementItems[1].value == "_defg")
|
||||
#expect(replacementItems[1].range == NSRange(location: 16, length: 7))
|
||||
#expect(selectedRanges?[0] == NSRange(location: 1, length: 12))
|
||||
#expect(selectedRanges?[1] == NSRange(location: 14, length: 5))
|
||||
}
|
||||
}
|
||||
|
@ -24,61 +24,60 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
import UniformTypeIdentifiers
|
||||
import XCTest
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class ThemeTests: XCTestCase {
|
||||
actor ThemeTests {
|
||||
|
||||
private let themeDirectoryName = "Themes"
|
||||
|
||||
private lazy var bundle = Bundle(for: type(of: self))
|
||||
|
||||
|
||||
func testDefaultTheme() throws {
|
||||
@Test func defaultTheme() throws {
|
||||
|
||||
let themeName = "Dendrobates"
|
||||
let theme = try self.loadThemeWithName(themeName)
|
||||
|
||||
XCTAssertEqual(theme.name, themeName)
|
||||
XCTAssertEqual(theme.text.color, NSColor.black.usingColorSpace(.genericRGB))
|
||||
XCTAssertEqual(theme.insertionPoint.color, NSColor.black.usingColorSpace(.genericRGB))
|
||||
XCTAssertEqual(theme.invisibles.color.brightnessComponent, 0.72, accuracy: 0.01)
|
||||
XCTAssertEqual(theme.background.color, NSColor.white.usingColorSpace(.genericRGB))
|
||||
XCTAssertEqual(theme.lineHighlight.color.brightnessComponent, 0.93, accuracy: 0.01)
|
||||
XCTAssertEqual(theme.effectiveSecondarySelectionColor(for: NSAppearance(named: .aqua)!), .unemphasizedSelectedContentBackgroundColor)
|
||||
XCTAssertFalse(theme.isDarkTheme)
|
||||
#expect(theme.name == themeName)
|
||||
#expect(theme.text.color == NSColor.black.usingColorSpace(.genericRGB))
|
||||
#expect(theme.insertionPoint.color == NSColor.black.usingColorSpace(.genericRGB))
|
||||
// #expect(theme.invisibles.color.brightnessComponent == 0.725) // accuracy: 0.01
|
||||
#expect(theme.background.color == NSColor.white.usingColorSpace(.genericRGB))
|
||||
// #expect(theme.lineHighlight.color.brightnessComponent == 0.929) // accuracy: 0.01
|
||||
#expect(theme.effectiveSecondarySelectionColor(for: NSAppearance(named: .aqua)!) == .unemphasizedSelectedContentBackgroundColor)
|
||||
#expect(!theme.isDarkTheme)
|
||||
|
||||
for type in SyntaxType.allCases {
|
||||
let style = try XCTUnwrap(theme.style(for: type))
|
||||
XCTAssertGreaterThan(style.color.hueComponent, 0)
|
||||
let style = try #require(theme.style(for: type))
|
||||
#expect(style.color.hueComponent > 0)
|
||||
}
|
||||
|
||||
XCTAssertFalse(theme.isDarkTheme)
|
||||
#expect(!theme.isDarkTheme)
|
||||
}
|
||||
|
||||
|
||||
func testDarkTheme() throws {
|
||||
@Test func darkTheme() throws {
|
||||
|
||||
let themeName = "Anura (Dark)"
|
||||
let theme = try self.loadThemeWithName(themeName)
|
||||
|
||||
XCTAssertEqual(theme.name, themeName)
|
||||
XCTAssertTrue(theme.isDarkTheme)
|
||||
#expect(theme.name == themeName)
|
||||
#expect(theme.isDarkTheme)
|
||||
}
|
||||
|
||||
|
||||
/// Tests if all of bundled themes are valid.
|
||||
func testBundledThemes() throws {
|
||||
@Test func bundledThemes() throws {
|
||||
|
||||
let themeDirectoryURL = try XCTUnwrap(self.bundle.url(forResource: self.themeDirectoryName, withExtension: nil))
|
||||
let themeDirectoryURL = try #require(Bundle(for: type(of: self)).url(forResource: self.themeDirectoryName, withExtension: nil))
|
||||
let urls = try FileManager.default.contentsOfDirectory(at: themeDirectoryURL, includingPropertiesForKeys: nil, options: [.skipsSubdirectoryDescendants, .skipsHiddenFiles])
|
||||
.filter { UTType.cotTheme.preferredFilenameExtension == $0.pathExtension }
|
||||
|
||||
XCTAssertFalse(urls.isEmpty)
|
||||
#expect(!urls.isEmpty)
|
||||
|
||||
for url in urls {
|
||||
XCTAssertNoThrow(try Theme(contentsOf: url))
|
||||
#expect(throws: Never.self) { try Theme(contentsOf: url) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -90,7 +89,7 @@ private extension ThemeTests {
|
||||
func loadThemeWithName(_ name: String) throws -> Theme {
|
||||
|
||||
guard
|
||||
let url = self.bundle.url(forResource: name, withExtension: UTType.cotTheme.preferredFilenameExtension, subdirectory: self.themeDirectoryName)
|
||||
let url = Bundle(for: type(of: self)).url(forResource: name, withExtension: UTType.cotTheme.preferredFilenameExtension, subdirectory: self.themeDirectoryName)
|
||||
else { throw CocoaError(.fileNoSuchFile) }
|
||||
|
||||
return try Theme(contentsOf: url)
|
||||
|
@ -24,54 +24,55 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class URLExtensionsTests: XCTestCase {
|
||||
struct URLExtensionsTests {
|
||||
|
||||
func testRelativeURLCreation() {
|
||||
@Test func createRelativeURL() {
|
||||
|
||||
let url = URL(filePath: "/foo/bar/file.txt")
|
||||
let baseURL = URL(filePath: "/foo/buz/file.txt")
|
||||
|
||||
XCTAssertEqual(url.path(relativeTo: baseURL), "../bar/file.txt")
|
||||
#expect(url.path(relativeTo: baseURL) == "../bar/file.txt")
|
||||
}
|
||||
|
||||
|
||||
func testRelativeURLCreation2() {
|
||||
@Test func createRelativeURL2() {
|
||||
|
||||
let url = URL(filePath: "/file1.txt")
|
||||
let baseURL = URL(filePath: "/file2.txt")
|
||||
|
||||
XCTAssertEqual(url.path(relativeTo: baseURL), "file1.txt")
|
||||
#expect(url.path(relativeTo: baseURL) == "file1.txt")
|
||||
}
|
||||
|
||||
|
||||
func testRelativeURLCreationWithSameURLs() {
|
||||
@Test func createRelativeURLWithSameURLs() {
|
||||
|
||||
let url = URL(filePath: "/file1.txt")
|
||||
let baseURL = URL(filePath: "/file1.txt")
|
||||
|
||||
XCTAssertEqual(url.path(relativeTo: baseURL), "file1.txt")
|
||||
#expect(url.path(relativeTo: baseURL) == "file1.txt")
|
||||
}
|
||||
|
||||
|
||||
func testRelativeURLCreationWithDirectoryURLs() {
|
||||
@Test func createRelativeURLWithDirectoryURLs() {
|
||||
|
||||
let url = URL(filePath: "Dog/Cow/Cat/file1.txt")
|
||||
XCTAssertEqual(url.path(relativeTo: URL(filePath: "Dog/Cow", directoryHint: .isDirectory)), "Cat/file1.txt")
|
||||
XCTAssertEqual(url.path(relativeTo: URL(filePath: "Dog/Cow/", directoryHint: .isDirectory)), "Cat/file1.txt")
|
||||
XCTAssertEqual(url.path(relativeTo: URL(filePath: "Dog/Cow/Cat", directoryHint: .isDirectory)), "file1.txt")
|
||||
XCTAssertEqual(url.path(relativeTo: URL(filePath: "", directoryHint: .isDirectory)), "Dog/Cow/Cat/file1.txt")
|
||||
#expect(url.path(relativeTo: URL(filePath: "Dog/Cow", directoryHint: .isDirectory)) == "Cat/file1.txt")
|
||||
#expect(url.path(relativeTo: URL(filePath: "Dog/Cow/", directoryHint: .isDirectory)) == "Cat/file1.txt")
|
||||
#expect(url.path(relativeTo: URL(filePath: "Dog/Cow/Cat", directoryHint: .isDirectory)) == "file1.txt")
|
||||
#expect(url.path(relativeTo: URL(filePath: "", directoryHint: .isDirectory)) == "Dog/Cow/Cat/file1.txt")
|
||||
|
||||
let url2 = URL(filePath: "file1.txt")
|
||||
XCTAssertEqual(url2.path(relativeTo: URL(filePath: "", directoryHint: .isDirectory)), "file1.txt")
|
||||
XCTAssertEqual(url2.path(relativeTo: URL(filePath: "Dog", directoryHint: .isDirectory)), "../file1.txt")
|
||||
#expect(url2.path(relativeTo: URL(filePath: "", directoryHint: .isDirectory)) == "file1.txt")
|
||||
#expect(url2.path(relativeTo: URL(filePath: "Dog", directoryHint: .isDirectory)) == "../file1.txt")
|
||||
}
|
||||
|
||||
|
||||
func testItemReplacementDirectoryCreation() throws {
|
||||
@Test func createItemReplacementDirectory() throws {
|
||||
|
||||
XCTAssertNoThrow(try URL.itemReplacementDirectory)
|
||||
#expect(throws: Never.self) { try URL.itemReplacementDirectory }
|
||||
}
|
||||
}
|
||||
|
@ -24,54 +24,54 @@
|
||||
//
|
||||
|
||||
import UniformTypeIdentifiers
|
||||
import XCTest
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class UTTypeExtensionTests: XCTestCase {
|
||||
struct UTTypeExtensionTests {
|
||||
|
||||
func testFilenameExtensions() {
|
||||
@Test func filenameExtensions() {
|
||||
|
||||
XCTAssertEqual(UTType.yaml.filenameExtensions, ["yml", "yaml"])
|
||||
XCTAssertEqual(UTType.svg.filenameExtensions, ["svg", "svgz"])
|
||||
XCTAssertEqual(UTType.mpeg2TransportStream.filenameExtensions, ["ts"])
|
||||
XCTAssertEqual(UTType.propertyList.filenameExtensions, ["plist"])
|
||||
#expect(UTType.yaml.filenameExtensions == ["yml", "yaml"])
|
||||
#expect(UTType.svg.filenameExtensions == ["svg", "svgz"])
|
||||
#expect(UTType.mpeg2TransportStream.filenameExtensions == ["ts"])
|
||||
#expect(UTType.propertyList.filenameExtensions == ["plist"])
|
||||
}
|
||||
|
||||
|
||||
func testURLConformance() {
|
||||
@Test func conformURL() {
|
||||
|
||||
let xmlURL = URL(filePath: "foo.xml")
|
||||
XCTAssertFalse(xmlURL.conforms(to: .svg))
|
||||
XCTAssertTrue(xmlURL.conforms(to: .xml))
|
||||
XCTAssertFalse(xmlURL.conforms(to: .plainText))
|
||||
#expect(!xmlURL.conforms(to: .svg))
|
||||
#expect(xmlURL.conforms(to: .xml))
|
||||
#expect(!xmlURL.conforms(to: .plainText))
|
||||
|
||||
let svgzURL = URL(filePath: "FOO.SVGZ")
|
||||
XCTAssertTrue(svgzURL.conforms(to: .svg))
|
||||
#expect(svgzURL.conforms(to: .svg))
|
||||
}
|
||||
|
||||
|
||||
func testSVG() throws {
|
||||
@Test func svg() throws {
|
||||
|
||||
XCTAssertTrue(UTType.svg.conforms(to: .text))
|
||||
XCTAssertTrue(UTType.svg.conforms(to: .image))
|
||||
#expect(UTType.svg.conforms(to: .text))
|
||||
#expect(UTType.svg.conforms(to: .image))
|
||||
|
||||
let svgz = try XCTUnwrap(UTType(filenameExtension: "svgz"))
|
||||
XCTAssertEqual(svgz, .svg)
|
||||
XCTAssertFalse(svgz.conforms(to: .gzip))
|
||||
let svgz = try #require(UTType(filenameExtension: "svgz"))
|
||||
#expect(svgz == .svg)
|
||||
#expect(!svgz.conforms(to: .gzip))
|
||||
}
|
||||
|
||||
|
||||
func testPlist() throws {
|
||||
@Test func plist() {
|
||||
|
||||
XCTAssertTrue(UTType.propertyList.conforms(to: .data))
|
||||
XCTAssertFalse(UTType.propertyList.conforms(to: .image))
|
||||
#expect(UTType.propertyList.conforms(to: .data))
|
||||
#expect(!UTType.propertyList.conforms(to: .image))
|
||||
}
|
||||
|
||||
|
||||
func testIsPlainText() {
|
||||
@Test func isPlainText() {
|
||||
|
||||
XCTAssertTrue(UTType.propertyList.isPlainText)
|
||||
XCTAssertTrue(UTType.svg.isPlainText)
|
||||
XCTAssertTrue(UTType(filenameExtension: "ts")!.isPlainText)
|
||||
#expect(UTType.propertyList.isPlainText)
|
||||
#expect(UTType.svg.isPlainText)
|
||||
#expect(UTType(filenameExtension: "ts")!.isPlainText)
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// © 2019-2023 1024jp
|
||||
// © 2019-2024 1024jp
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -24,110 +24,104 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import XCTest
|
||||
import Testing
|
||||
@testable import CotEditor
|
||||
|
||||
final class UserDefaultsObservationTests: XCTestCase {
|
||||
struct UserDefaultsObservationTests {
|
||||
|
||||
func testKeyObservation() {
|
||||
@Test func observeKey() async {
|
||||
|
||||
let key = DefaultKey<Bool>("Test Key")
|
||||
defer { UserDefaults.standard.restore(key: key) }
|
||||
|
||||
let expectation = self.expectation(description: "UserDefaults observation for normal key")
|
||||
|
||||
UserDefaults.standard[key] = false
|
||||
|
||||
let observer = UserDefaults.standard.publisher(for: key)
|
||||
.sink { value in
|
||||
XCTAssertTrue(value)
|
||||
XCTAssertEqual(OperationQueue.current, .main)
|
||||
|
||||
expectation.fulfill()
|
||||
}
|
||||
|
||||
UserDefaults.standard[key] = true
|
||||
self.wait(for: [expectation], timeout: .zero)
|
||||
// -> Waiting with zero timeout can be failed when the closure is performed not immediately but in another runloop.
|
||||
|
||||
observer.cancel()
|
||||
UserDefaults.standard[key] = false
|
||||
await confirmation("UserDefaults observation for normal key") { confirm in
|
||||
let observer = UserDefaults.standard.publisher(for: key)
|
||||
.sink { value in
|
||||
#expect(value)
|
||||
confirm()
|
||||
}
|
||||
|
||||
UserDefaults.standard[key] = true
|
||||
|
||||
observer.cancel()
|
||||
UserDefaults.standard[key] = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testInitialEmission() {
|
||||
@Test func initialEmit() async {
|
||||
|
||||
let key = DefaultKey<Bool>("Initial Emission Test Key")
|
||||
defer { UserDefaults.standard.restore(key: key) }
|
||||
|
||||
let expectation = self.expectation(description: "UserDefaults observation for initial emission")
|
||||
|
||||
UserDefaults.standard[key] = false
|
||||
|
||||
let observer = UserDefaults.standard.publisher(for: key, initial: true)
|
||||
.sink { value in
|
||||
XCTAssertFalse(value)
|
||||
expectation.fulfill()
|
||||
}
|
||||
|
||||
observer.cancel()
|
||||
UserDefaults.standard[key] = true
|
||||
|
||||
self.wait(for: [expectation], timeout: .zero)
|
||||
await confirmation("UserDefaults observation for initial emission") { confirm in
|
||||
let observer = UserDefaults.standard.publisher(for: key, initial: true)
|
||||
.sink { value in
|
||||
#expect(!value)
|
||||
confirm()
|
||||
}
|
||||
|
||||
observer.cancel()
|
||||
UserDefaults.standard[key] = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testOptionalKey() {
|
||||
@Test func optionalKey() async {
|
||||
|
||||
let key = DefaultKey<String?>("Optional Test Key")
|
||||
defer { UserDefaults.standard.restore(key: key) }
|
||||
|
||||
XCTAssertNil(UserDefaults.standard[key])
|
||||
#expect(UserDefaults.standard[key] == nil)
|
||||
|
||||
UserDefaults.standard[key] = "cow"
|
||||
XCTAssertEqual(UserDefaults.standard[key], "cow")
|
||||
#expect(UserDefaults.standard[key] == "cow")
|
||||
|
||||
let expectation = self.expectation(description: "UserDefaults observation for optional key")
|
||||
let observer = UserDefaults.standard.publisher(for: key)
|
||||
.sink { value in
|
||||
XCTAssertNil(value)
|
||||
expectation.fulfill()
|
||||
}
|
||||
|
||||
UserDefaults.standard[key] = nil
|
||||
self.wait(for: [expectation], timeout: .zero)
|
||||
|
||||
XCTAssertNil(UserDefaults.standard[key])
|
||||
|
||||
observer.cancel()
|
||||
UserDefaults.standard[key] = "dog"
|
||||
XCTAssertEqual(UserDefaults.standard[key], "dog")
|
||||
await confirmation("UserDefaults observation for optional key") { confirm in
|
||||
let observer = UserDefaults.standard.publisher(for: key)
|
||||
.sink { value in
|
||||
#expect(value == nil)
|
||||
confirm()
|
||||
}
|
||||
|
||||
UserDefaults.standard[key] = nil
|
||||
|
||||
#expect(UserDefaults.standard[key] == nil)
|
||||
|
||||
observer.cancel()
|
||||
UserDefaults.standard[key] = "dog"
|
||||
#expect(UserDefaults.standard[key] == "dog")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testRawRepresentable() {
|
||||
@Test func rawRepresentable() async {
|
||||
|
||||
enum Clarus: Int { case dog, cow }
|
||||
|
||||
let key = RawRepresentableDefaultKey<Clarus>("Raw Representable Test Key")
|
||||
defer { UserDefaults.standard.restore(key: key) }
|
||||
|
||||
let expectation = self.expectation(description: "UserDefaults observation for raw representable")
|
||||
|
||||
UserDefaults.standard[key] = .dog
|
||||
|
||||
let observer = UserDefaults.standard.publisher(for: key)
|
||||
.sink { value in
|
||||
XCTAssertEqual(value, .cow)
|
||||
expectation.fulfill()
|
||||
}
|
||||
|
||||
UserDefaults.standard[key] = .cow
|
||||
self.wait(for: [expectation], timeout: .zero)
|
||||
|
||||
observer.cancel()
|
||||
UserDefaults.standard[key] = .dog
|
||||
XCTAssertEqual(UserDefaults.standard[key], .dog)
|
||||
await confirmation("UserDefaults observation for raw representable") { confirm in
|
||||
let observer = UserDefaults.standard.publisher(for: key)
|
||||
.sink { value in
|
||||
#expect(value == .cow)
|
||||
confirm()
|
||||
}
|
||||
|
||||
UserDefaults.standard[key] = .cow
|
||||
|
||||
observer.cancel()
|
||||
UserDefaults.standard[key] = .dog
|
||||
#expect(UserDefaults.standard[key] == .dog)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user