// // UnitTests.swift // CodeEditModules/CodeEditUtilsTests // // Created by Lukas Pistrol on 01.05.22. // import Foundation import SwiftUI import XCTest @testable import CodeEdit final class CodeEditUtilsExtensionsUnitTests: XCTestCase { // MARK: - COLOR + HEX func testColorConversionFromHEXString() throws { let colorString = "#123456" let color = Color(hex: colorString) XCTAssertEqual(colorString, color.hexString) } func testNSColorConversionFromHEXString() throws { let colorString = "#123456" let color = NSColor(hex: colorString) XCTAssertEqual(colorString, color.hexString) } func testColorConversionFromHEXInt() throws { let colorInt = 0x123456 let color = Color(hex: colorInt) XCTAssertEqual(colorInt, color.hex) } func testNSColorConversionFromHEXInt() throws { let colorInt = 0x123456 let color = NSColor(hex: colorInt) XCTAssertEqual(colorInt, color.hex) } func testColorConversionAlphaValue() throws { let alpha = 0.25 let color = Color(hex: "#123456", alpha: alpha) XCTAssertEqual(alpha, color.alphaComponent) } func testNSColorConversionAlphaValue() throws { let alpha = 0.25 let color = NSColor(hex: "#123456", alpha: alpha) XCTAssertEqual(alpha, color.alphaComponent) } // MARK: - DATE + FORMATTED func testRelativeDateStringMinutes() throws { let date = Date.now.addingTimeInterval(-61) let string = date.relativeStringToNow(locale: Locale(identifier: "en_US")) XCTAssertEqual("1 min. ago", string) } func testRelativeDateStringHours() throws { let date = Date.now.addingTimeInterval(-3_601) let string = date.relativeStringToNow(locale: Locale(identifier: "en_US")) XCTAssertEqual("1 hr. ago", string) } func testRelativeDateStringDays() throws { let date = Date.now.addingTimeInterval(-86_400) let string = date.relativeStringToNow(locale: Locale(identifier: "en_US")) XCTAssertEqual("yesterday", string) } // MARK: - STRING + MD5 func testMD5GenerationCaseSensitive() throws { let testString = "CodeEdit" let md5 = testString.md5(caseSensitive: true) let result = "8ba8c8fd0442f7bae4d441e2a3fda706" XCTAssertEqual(result, md5) } func testMD5Generation() throws { let testString = "CodeEdit" let md5 = testString.md5(caseSensitive: false) let result = "4cdf122ff382a2d929eddc1a63473ec1" XCTAssertEqual(result, md5) } // MARK: - STRING + SHA256 func testSHA256GenerationCaseSensitive() throws { let testString = "CodeEdit" let md5 = testString.sha256(caseSensitive: true) let result = "52125689c088f1783e53c48db78a4fe7b3fa10b12d8fba205fcf054e5ef3789a" XCTAssertEqual(result, md5) } func test256Generation() throws { let testString = "CodeEdit" let md5 = testString.sha256(caseSensitive: false) let result = "7c3f327eab3860fc823a99623b348afbf1d7aebaec5d21289fbaeab0f6340e4a" XCTAssertEqual(result, md5) } // MARK: - STRING + REMOVING OCCURRENCES func testRemovingNewLines() throws { let string = "Hello, \nWorld!" let withoutNewLines = string.removingNewLines() let result = "Hello, World!" XCTAssertEqual(result, withoutNewLines) } func testRemovingSpaces() throws { let string = "Hello, World!" let withoutSpaces = string.removingSpaces() let result = "Hello,World!" XCTAssertEqual(result, withoutSpaces) } // MARK: - STRING + VALID FILE NAME func testValidFileName() { let validCases = [ "hello world", "newSwiftFile.swift", "documento_español.txt", "dokument_deutsch.pdf", "rapport_français.docx", "レポート_日本語.xlsx", "отчет_русский.pptx", "보고서_한국어.txt", "文件_中文.pdf", "dokument_svenska.txt", "relatório_português.docx", "relazione_italiano.pdf", "file_with_emoji_😊.txt", "emoji_report_📄.pdf", "archivo_con_emoji_🌟.docx", "文件和表情符号_🚀.txt", "rapport_avec_emoji_🎨.pptx", // 255 characters (exactly the maximum) String((0..<255).map({ _ in "abcd".randomElement() ?? Character("") })) ] for validCase in validCases { XCTAssertTrue(validCase.isValidFilename, "Detected invalid case \"\(validCase)\", should be valid.") } } func testInvalidFileName() { // The only limitations for macOS file extensions is no ':' and no NULL characters and 255 UTF16 char limit. let invalidCases = [ "", ":", "\0", "Hell\0 World!", "export:2024-04-12.txt", // 256 characters (1 too long) String((0..<256).map({ _ in "abcd".randomElement() ?? Character("") })) ] for invalidCase in invalidCases { XCTAssertFalse(invalidCase.isValidFilename, "Detected valid case \"\(invalidCase)\", should be invalid.") } } // MARK: - STRING + ESCAPED func testEscapeQuotes() { let string = #"this/is/"a path/Hello "world"# XCTAssertEqual(string.escapedQuotes(), #"this/is/\"a path/Hello \"world"#) } func testEscapeQuotesForAlreadyEscapedString() { let string = #"this/is/"a path/Hello \"world"# XCTAssertEqual(string.escapedQuotes(), #"this/is/\"a path/Hello \"world"#) } func testEscapedDirectory() { let path = #"/Hello World/ With Spaces/ And " Characters "# XCTAssertEqual(path.escapedDirectory(), #""/Hello World/ With Spaces/ And \" Characters ""#) } // MARK: - URL + Contains func testURLContainsSubPath() { XCTAssertTrue(URL(filePath: "/Users/Bob/Desktop").containsSubPath(URL(filePath: "/Users/Bob/Desktop/file.txt"))) XCTAssertFalse(URL(filePath: "/Users/Bob/Desktop").containsSubPath(URL(filePath: "/Users/Bob/Desktop/"))) XCTAssertFalse(URL(filePath: "/Users/Bob/Desktop").containsSubPath(URL(filePath: "/Users/Bob/"))) XCTAssertTrue(URL(filePath: "/Users/Bob/Desktop").containsSubPath(URL(filePath: "/Users/Bob/Desktop/Folder"))) } func testURLSharedComponentsCount() { // URL Treats the leading `/` as a component, so these all appear to have + 1 but are correct. XCTAssertEqual( URL(filePath: "/Users/Bob/Desktop").sharedComponents(URL(filePath: "/Users/Bob/Desktop/file.txt")), 4 ) XCTAssertEqual( URL(filePath: "/Users/Bob/Desktop").sharedComponents(URL(filePath: "/Users/Bob/Desktop/")), 4 ) XCTAssertEqual( URL(filePath: "/Users/Bob/Desktop").sharedComponents(URL(filePath: "/Users/Bob/")), 3 ) XCTAssertEqual( URL(filePath: "/Users/Bob/Desktop").sharedComponents(URL(filePath: "/Users/Bob/Desktop/Folder")), 4 ) XCTAssertEqual( URL(filePath: "/Users/Bob/Desktop").sharedComponents(URL(filePath: "/Some Other/ Path ")), 1 ) } }