diff --git a/CHANGELOG.md b/CHANGELOG.md index 826f7a046..7d2f4a9f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/Tests/ArithmeticsTests.swift b/Tests/ArithmeticsTests.swift index 39142ab19..778ab6dd3 100644 --- a/Tests/ArithmeticsTests.swift +++ b/Tests/ArithmeticsTests.swift @@ -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]) } } diff --git a/Tests/BracePairTests.swift b/Tests/BracePairTests.swift index 40ed3cf38..7fc7be5e1 100644 --- a/Tests/BracePairTests.swift +++ b/Tests/BracePairTests.swift @@ -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)) } } diff --git a/Tests/CharacterInfoTests.swift b/Tests/CharacterInfoTests.swift index 1fc880dc8..22161f6ea 100644 --- a/Tests/CharacterInfoTests.swift +++ b/Tests/CharacterInfoTests.swift @@ -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, "") - XCTAssertEqual(character.blockName, "High Surrogates") + #expect(character.unicodeName == "") + #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, "") + #expect(charInfo.isComplex) + #expect(charInfo.character.unicodeScalars.map(\.codePoint) == ["U+0031", "U+FE0F", "U+20E3"]) + #expect(charInfo.localizedDescription == "") } - 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"]) } } diff --git a/Tests/CollectionTests.swift b/Tests/CollectionTests.swift index ec85fccd1..92c2b7b0a 100644 --- a/Tests/CollectionTests.swift +++ b/Tests/CollectionTests.swift @@ -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 })) } } } diff --git a/Tests/ComparableTests.swift b/Tests/ComparableTests.swift index 92206d109..055768754 100644 --- a/Tests/ComparableTests.swift +++ b/Tests/ComparableTests.swift @@ -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), diff --git a/Tests/DebouncerTests.swift b/Tests/DebouncerTests.swift index 310a7542a..88828bd80 100644 --- a/Tests/DebouncerTests.swift +++ b/Tests/DebouncerTests.swift @@ -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) } } diff --git a/Tests/EditedRangeSetTests.swift b/Tests/EditedRangeSetTests.swift index 7d2ec1d9a..ea8f149fe 100644 --- a/Tests/EditedRangeSetTests.swift +++ b/Tests/EditedRangeSetTests.swift @@ -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() + } } } diff --git a/Tests/EditorCounterTests.swift b/Tests/EditorCounterTests.swift index 196775189..ba1914aa0 100644 --- a/Tests/EditorCounterTests.swift +++ b/Tests/EditorCounterTests.swift @@ -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) } } diff --git a/Tests/EncodingDetectionTests.swift b/Tests/EncodingDetectionTests.swift index 7c6e80b0a..a73a3296a 100644 --- a/Tests/EncodingDetectionTests.swift +++ b/Tests/EncodingDetectionTests.swift @@ -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 = "" - 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("".scanEncodingDeclaration(upTo: 128), .utf8) + #expect("".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) diff --git a/Tests/FileDropItemTests.swift b/Tests/FileDropItemTests.swift index 3df42416d..1b9e711c3 100644 --- a/Tests/FileDropItemTests.swift +++ b/Tests/FileDropItemTests.swift @@ -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)) } } diff --git a/Tests/FilePermissionTests.swift b/Tests/FilePermissionTests.swift index 9a963b945..4f30e6907 100644 --- a/Tests/FilePermissionTests.swift +++ b/Tests/FilePermissionTests.swift @@ -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) } } diff --git a/Tests/FontExtensionTests.swift b/Tests/FontExtensionTests.swift index 0b2e0c645..ac446ac7a 100644 --- a/Tests/FontExtensionTests.swift +++ b/Tests/FontExtensionTests.swift @@ -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 } } diff --git a/Tests/FormatStylesTests.swift b/Tests/FormatStylesTests.swift index ea068fad8..50b9cb3ea 100644 --- a/Tests/FormatStylesTests.swift +++ b/Tests/FormatStylesTests.swift @@ -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) } } diff --git a/Tests/FourCharCodeTests.swift b/Tests/FourCharCodeTests.swift index 2bea53b73..c029919cc 100644 --- a/Tests/FourCharCodeTests.swift +++ b/Tests/FourCharCodeTests.swift @@ -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'")) } } diff --git a/Tests/FuzzyRangeTests.swift b/Tests/FuzzyRangeTests.swift index 8b71cdab0..18bb65f96 100644 --- a/Tests/FuzzyRangeTests.swift +++ b/Tests/FuzzyRangeTests.swift @@ -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) } } diff --git a/Tests/GeometryTests.swift b/Tests/GeometryTests.swift index f1bced095..ace915153 100644 --- a/Tests/GeometryTests.swift +++ b/Tests/GeometryTests.swift @@ -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) } } diff --git a/Tests/IncompatibleCharacterTests.swift b/Tests/IncompatibleCharacterTests.swift index d86a8aa8c..0c59097c4 100644 --- a/Tests/IncompatibleCharacterTests.swift +++ b/Tests/IncompatibleCharacterTests.swift @@ -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) } } diff --git a/Tests/LineEndingScannerTests.swift b/Tests/LineEndingScannerTests.swift index 48034a24c..4daa85ce6 100644 --- a/Tests/LineEndingScannerTests.swift +++ b/Tests/LineEndingScannerTests.swift @@ -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..] = [ @@ -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") } } diff --git a/Tests/LineRangeCacheableTests.swift b/Tests/LineRangeCacheableTests.swift index bdde6787a..fe67701ce 100644 --- a/Tests/LineRangeCacheableTests.swift +++ b/Tests/LineRangeCacheableTests.swift @@ -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.. 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)]) } } diff --git a/Tests/ShiftJISTests.swift b/Tests/ShiftJISTests.swift index 019797078..342458d7c 100644 --- a/Tests/ShiftJISTests.swift +++ b/Tests/ShiftJISTests.swift @@ -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("¥") == "¥")) } } diff --git a/Tests/ShortcutTests.swift b/Tests/ShortcutTests.swift index 28e53b96c..43480852f 100644 --- a/Tests/ShortcutTests.swift +++ b/Tests/ShortcutTests.swift @@ -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) } } diff --git a/Tests/SnippetTests.swift b/Tests/SnippetTests.swift index 543fd3aaa..1a6b5cb32 100644 --- a/Tests/SnippetTests.swift +++ b/Tests/SnippetTests.swift @@ -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: "

<<>><<>>

") let (string, selections) = snippet.insertion(selectedString: "abc") - XCTAssertEqual(string, "

abc

") - XCTAssertEqual(selections, [NSRange(location: 7, length: 0)]) + #expect(string == "

abc

") + #expect(selections == [NSRange(location: 7, length: 0)]) } - func testMultipleLines() { + @Test func multipleLines() { let format = """
    @@ -55,9 +56,9 @@ final class SnippetTests: XCTestCase {
""" - 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 {
  • """ - 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) } } diff --git a/Tests/StringCollectionTests.swift b/Tests/StringCollectionTests.swift index a0ff057a2..5d7ae33c7 100644 --- a/Tests/StringCollectionTests.swift +++ b/Tests/StringCollectionTests.swift @@ -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") } } diff --git a/Tests/StringCommentingTests.swift b/Tests/StringCommentingTests.swift index 3632e7283..a29486533 100644 --- a/Tests/StringCommentingTests.swift +++ b/Tests/StringCommentingTests.swift @@ -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)) } } diff --git a/Tests/StringExtensionsTests.swift b/Tests/StringExtensionsTests.swift index e78b98089..08582cc76 100644 --- a/Tests/StringExtensionsTests.swift +++ b/Tests/StringExtensionsTests.swift @@ -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: - 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.. 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: "") } } } diff --git a/Tests/StringIndentationTests.swift b/Tests/StringIndentationTests.swift index 89b4b84b9..c9b80a6f4 100644 --- a/Tests/StringIndentationTests.swift +++ b/Tests/StringIndentationTests.swift @@ -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) } } diff --git a/Tests/StringLineProcessingTests.swift b/Tests/StringLineProcessingTests.swift index e732a781a..7e5256714 100644 --- a/Tests/StringLineProcessingTests.swift +++ b/Tests/StringLineProcessingTests.swift @@ -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) } } diff --git a/Tests/SyntaxTests.swift b/Tests/SyntaxTests.swift index 11e56ee47..23bf70622 100644 --- a/Tests/SyntaxTests.swift +++ b/Tests/SyntaxTests.swift @@ -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) } } diff --git a/Tests/TextClippingTests.swift b/Tests/TextClippingTests.swift index 3d01d841c..a1694c1c1 100644 --- a/Tests/TextClippingTests.swift +++ b/Tests/TextClippingTests.swift @@ -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🐄") } } diff --git a/Tests/TextFindTests.swift b/Tests/TextFindTests.swift index a90fcfd0c..7cc26851a 100644 --- a/Tests/TextFindTests.swift +++ b/Tests/TextFindTests.swift @@ -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)) } } diff --git a/Tests/ThemeTests.swift b/Tests/ThemeTests.swift index 70940c32f..05d76d987 100644 --- a/Tests/ThemeTests.swift +++ b/Tests/ThemeTests.swift @@ -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) diff --git a/Tests/URLExtensionsTests.swift b/Tests/URLExtensionsTests.swift index 95d0ce4fc..c6f43f4bb 100644 --- a/Tests/URLExtensionsTests.swift +++ b/Tests/URLExtensionsTests.swift @@ -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 } } } diff --git a/Tests/UTTypeExtensionTests.swift b/Tests/UTTypeExtensionTests.swift index 18020f94b..2c83417fe 100644 --- a/Tests/UTTypeExtensionTests.swift +++ b/Tests/UTTypeExtensionTests.swift @@ -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) } } diff --git a/Tests/UserDefaultsObservationTests.swift b/Tests/UserDefaultsObservationTests.swift index 23ccc0c5d..c92fbc8cd 100644 --- a/Tests/UserDefaultsObservationTests.swift +++ b/Tests/UserDefaultsObservationTests.swift @@ -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("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("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("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("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) + } } }