Skip to content

Instantly share code, notes, and snippets.

@WF-Chiang
Created July 9, 2019 04:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save WF-Chiang/fbaebc7533ae48b463941471ac7c1acf to your computer and use it in GitHub Desktop.
Save WF-Chiang/fbaebc7533ae48b463941471ac7c1acf to your computer and use it in GitHub Desktop.
//
// SwiftAdvanceTests.swift
// SwiftAdvanceTests
//
// Created by wuufone on 2018/9/17.
// Copyright © 2018年 wuufone. All rights reserved.
//
import XCTest
@testable import SwiftAdvance
class SwiftAdvanceTests: XCTestCase {
func testBoundInt() {
XCTAssertEqual(-9223372036854775808, Int.min)
XCTAssertEqual(9223372036854775807, Int.max)
XCTAssertEqual((pow(Decimal(2), Int(63))-1 as NSDecimalNumber).intValue, Int.max)
}
func testFormat() {
XCTAssertEqual(10000000, 1000_0000)
/* 指數 (exponent, exp)。 e 表示十進位;p 表示二進位。*/
XCTAssertEqual(100.1, 1.001e2)
XCTAssertEqual(100.1, 1001e-1)
XCTAssertEqual(0x4, 0x1p2)
}
func testTypeAlias() {
typealias Location = CGPoint
XCTAssertEqual(Location(), CGPoint())
}
func testOptional() {
var aVariable: Any?
XCTAssertNil(aVariable)
aVariable = EMPTY
XCTAssertNotNil(aVariable)
}
func testOptionalBinding() {
class MyView: UIView {
var button: UIButton?
}
let myViewInstance = MyView()
guard let button = myViewInstance.button else {
XCTAssertNil(myViewInstance.button)
return
}
XCTAssertNil(button)
}
func testIfLetSentence() {
let aValue: String? = nil
if let anotherValue = aValue {
XCTFail("\(anotherValue) 應該是 nil,此行不該被執行。")
}
guard aValue == nil else {
XCTFail("\(String(describing: aValue)) 應該是 nil,此行不該被執行。")
return
}
}
func testFunctionWithOptionalReturn() {
func findSomething(name: String) -> NSObject? {
return nil
}
var somethingDone: Bool = false
if let foundThing = findSomething(name: "Stuff") {
print("This is a say way to use \(foundThing).")
somethingDone = true
}
XCTAssertFalse(somethingDone)
}
func testOptionalChaining() {
class Person {
var job: Job?
}
class Job {
var title: String
init(title: String) {
self.title = title
}
}
let employee = Person()
let engineer = Job(title: "engineer")
employee.job = engineer
/* not use optional chaining
var title: String = ""
if employee.job != nil {
title = employee.job.title
}
XCTAssertEqual("engineer", title)
*/
// 使用 optional chaining (very gracefully)
if let title = employee.job?.title {
XCTAssertEqual("engineer", title)
} else {
XCTFail()
}
}
func testConvertingErrorsToOptionalValues() {
func someThrowingFunction() throws -> String { return "test" }
// 不使用 do / catch 的話: Errors thrown from here are not handled
do {
let result = try someThrowingFunction()
XCTAssertEqual("test", result)
} catch {}
// 使用 try? (very gracefully)
XCTAssertEqual("test", try? someThrowingFunction())
// 在確定不會產生 Error 的情形下使用
XCTAssertEqual("test", try! someThrowingFunction())
}
func testClassPropertiesWithOptional() {
class SomeClass {
var property1: Any?
var proeprty2: Any?
}
}
func testClassHasProperties() {
class Book {
private(set) var title: String?
init(title: String) {
self.title = title
}
}
let aBook = Book(title: "Learning Swift")
XCTAssertEqual("Learning Swift", aBook.title)
// aBook.title = "Learning Swift V2"
}
func testComputedProperty() {
class Rect {
var width: Float
var height: Float
var area: Float {
return self.width * self.height
}
init (width: Float, height: Float) {
self.width = width
self.height = height
}
}
let aRect = Rect(width: 5, height: 2)
XCTAssertEqual(10, aRect.area)
}
func testClassHasPropertiesSwiftStyle() {
class Book {
var title: String? = nil
private var _isbn: String? = nil
var isbn: String? {
get { return _isbn }
set {
if _isbn == nil { // _isbn 只有在為 nil 時才能被變更
_isbn = newValue
}
}
}
}
let aBook = Book()
aBook.title = "Learning Swift"
aBook.isbn = "1111111111"
XCTAssertEqual("1111111111", aBook.isbn)
aBook.isbn = "2222222222" // 試圖變更 isbn 值
XCTAssertEqual("1111111111", aBook.isbn) // 斷言:isbn 不會改變
}
func testWatchProperties() {
class Book {
var oldTitle: String? = nil // 舊標題的值
private var _title: String? = nil
var title: String? {
get { return _title }
set {
oldTitle = _title
_title = newValue
}
}
}
let aBook = Book()
aBook.title = "學習 Swift 基礎"
XCTAssertEqual("學習 Swift 基礎", aBook.title)
aBook.title = "學習 Swift 進階"
XCTAssertEqual("學習 Swift 基礎", aBook.oldTitle)
XCTAssertEqual("學習 Swift 進階", aBook.title)
}
func testWatchProperitesWithObserver() {
class Book {
var oldTitle: String? = nil
var newTitle: String? = nil
private var _title: String? = nil
var title: String? {
willSet {
newTitle = newValue
}
didSet {
oldTitle = oldValue
}
}
}
let aBook = Book()
aBook.title = "學習 Swift 基礎"
XCTAssertEqual("學習 Swift 基礎", aBook.title)
aBook.title = "學習 Swift 進階"
XCTAssertEqual("學習 Swift 基礎", aBook.oldTitle)
XCTAssertEqual("學習 Swift 進階", aBook.title)
}
func testPropertyObservers() {
class WebForm {
var oldEmail: String? = nil
var newEmail: String? = nil
var email: String {
willSet {
self.newEmail = newValue
}
didSet {
self.oldEmail = oldValue
}
}
init(email: String) {
self.email = email
}
}
// 使用建構子設值,並不會執行 willSet 和 didSet
let webForm = WebForm(email: "old@abc.com")
XCTAssertEqual(webForm.oldEmail, nil)
XCTAssertEqual(webForm.newEmail, nil)
// 使用 email 特性的隱含 setter 時,會執行 willSet 和 didSet
webForm.email = "new@abc.com"
XCTAssertEqual(webForm.oldEmail, "old@abc.com")
XCTAssertEqual(webForm.newEmail, "new@abc.com")
}
func testCreateEmptyArray() {
let emptyArray = [String]()
XCTAssertTrue(type(of: emptyArray) == Array<String>.self)
let emptyArray2 = Array<String>()
XCTAssertTrue(type(of: emptyArray) == type(of: emptyArray2))
}
func testWalkThroughArray() {
// devices 為陣列
// iPhone 索引值為 0;iPad 為 1; iPod Touch 為 2
let devices = ["iPhone", "iPad", "iPod Touch"]
// 使用 for-in 語法遍歷陣列中的每個元素
var device: String?
for _device in devices {
device = _device
}
// 斷定: device 的值為陣列的最後一個元素
XCTAssertEqual("iPod Touch", device)
/* One-Sided Ranges */
for _device in devices[...1] { // 只遍歷索引小於等於 1 的元素
device = _device
}
XCTAssertEqual("iPad", device)
for _device in devices[..<1] { // 只遍歷索引小於 1 的元素
device = _device
}
XCTAssertEqual("iPhone", device)
for _device in devices[1...] { // 只遍歷索引大於 1 的元素
device = _device
}
XCTAssertEqual("iPod Touch", device)
}
func testOtherArrayOperation() {
var someInts = [Int]()
XCTAssertTrue(someInts.isEmpty) // 以 isEmpty 驗證陣列為空
// 陣列元素的增加
someInts.append(100)
XCTAssertEqual(100, someInts[0])
// 以單一值,填充給指定個數元素至陣列
let location = Array(repeating: 0, count: 3)
XCTAssertEqual([0, 0, 0], location)
// 陣列的加法
XCTAssertEqual([0, 1, 2, 3], [0, 1] + [2, 3])
// XCTAssertEqual([0, 1, 2], [0, 1, 2, 3] - [3]) // 減法行不通
// 陣列元素的移除
someInts = [0, 1, 2, 3]
someInts.remove(at: 3)
XCTAssertEqual([0, 1, 2], someInts)
}
func testEmptySet() {
let emails: Set<String> = Set<String>()
XCTAssertTrue(emails.isEmpty)
}
func testEachOneSetElementIsUnique() {
var emails: Set<String> = Set<String>()
XCTAssertTrue(emails.isEmpty)
emails.insert("tom@abc.com")
emails.insert("mac@abc.com")
XCTAssertTrue(emails.count == 2)
// 無法加入重復的元素
let (success, _) = emails.insert("mac@abc.com")
XCTAssertFalse(success)
XCTAssertTrue(emails.count == 2)
}
func testSupersetAndSubset() {
let emails: Set<String> = ["tom@abc.com", "mac@abc.com"]
let email: Set<String> = ["tom@abc.com"]
XCTAssertTrue(email.isSubset(of: emails))
XCTAssertTrue(emails.isSuperset(of: email))
}
func testSetOperation() {
let emails: Set<String> = ["tom@abc.com", "mac@abc.com"]
var email: Set<String> = ["tom@abc.com"]
// 交集
XCTAssertEqual(emails.intersection(email), ["tom@abc.com"])
// 差集
XCTAssertEqual(emails.subtracting(email), ["mac@abc.com"])
// 對稱差
email.insert("kim@abc.com")
XCTAssertEqual(emails.symmetricDifference(email), ["mac@abc.com", "kim@abc.com"])
// 聯集
XCTAssertEqual(emails.union(email), ["tom@abc.com", "mac@abc.com", "kim@abc.com"])
// 不交集
let newEmail: Set<String> = ["new@abc.com"]
XCTAssertTrue(emails.isDisjoint(with: newEmail))
XCTAssertTrue(newEmail.isDisjoint(with: emails))
}
func testGenerateSetFromSet() {
let emails: Set<String> = ["tom@abc.com", "mac@abc.com"]
let moreEmails = NSMutableSet(set: emails)
moreEmails.add("joe@abc.com")
XCTAssertEqual(3, moreEmails.count)
XCTAssertTrue(emails.isSubset(of: moreEmails as! Set<String>))
}
func testSortedSet() {
let emails: Set<String> = ["tom@abc.com", "mac@abc.com"]
var sortedEmails = Array<String>()
for e in emails.sorted() {
sortedEmails.append(e)
}
XCTAssertEqual("mac@abc.com", sortedEmails.first)
XCTAssertEqual("tom@abc.com", sortedEmails.last)
}
func testCreateEmptyDictionary() {
let emptyDictionary = [String:Float]()
XCTAssertTrue(type(of: emptyDictionary) == Dictionary<String, Float>.self)
let emptyDictionary2 = Dictionary<String, Float>()
XCTAssertTrue(type(of: emptyDictionary) == type(of: emptyDictionary2))
}
func testSimpleDictionary() {
var simpleMembers: [Int: String] = [1: "John", 2: "Tom", 3: "Doris"]
XCTAssertTrue(simpleMembers[2] == "Tom")
}
func testComplexDictionary() {
var members: [[String: String]] = [
["name": "John",
"email": "john@abc.com",
"id": "1"],
["name": "Tom",
"email": "tom@abc.com",
"id": "2"],
["name": "Doris",
"email": "doris@abc.com",
"id": "3"],
]
XCTAssertEqual(members[0]["email"], "john@abc.com")
XCTAssertEqual(members[1]["name"], "Tom")
XCTAssertEqual(members[2]["id"], "3")
}
func testDictionaryUpdate() {
var members: [[String: String]] = [
["name": "John",
"email": "john@abc.com",
"id": "1"],
["name": "Tom",
"email": "tom@abc.com",
"id": "2"]
]
members[1].updateValue("tony@abc.com", forKey: "email")
members[1].updateValue("Tony", forKey: "name")
XCTAssertEqual(members[1]["name"], "Tony")
}
func testThroughOutDictionary() {
let members: [[String: String]] = [
["name": "John",
"email": "john@abc.com",
"id": "1"],
["name": "Tom",
"email": "tom@abc.com",
"id": "2"],
["name": "Doris",
"email": "doris@abc.com",
"id": "3"],
]
var memberNames: Set<String> = Set<String>()
for member in members {
let memberInfo: [String: String] = member as [String: String]
for (key, value) in memberInfo { // 使用 Tuple + for-in 結合
if key == "name" {
memberNames.insert(value)
}
}
}
XCTAssertEqual(memberNames, Set<String>(arrayLiteral: "John", "Tom", "Doris"))
}
func testTupleGetElementByIndex() {
let aTuple = (1, "someone's name", true)
XCTAssertEqual("someone's name", aTuple.1)
}
func testTuplePositionParameters() {
let (_, _, z) = (1, 2, 3)
XCTAssertEqual(3, z)
let (_, y, _) = (1, 2, 3)
XCTAssertEqual(2, y)
}
func testTupleHasParameterLabel() {
let vector3D = (x: 1, y: 2, z: 3)
XCTAssertEqual(2, vector3D.y)
}
func testCompareBetweenTuples() {
let vector3D = (x: 1, y: 2, z: 3)
XCTAssertEqual(2, vector3D.y)
let anotherVector3D = (x: 1, y:2, z: 4)
XCTAssertTrue(vector3D < anotherVector3D)
}
func testTupleWithSwitch() {
let xValue = Int(arc4random_uniform(5) + 1)
let yValue = Int(arc4random_uniform(5) + 1)
let point = (xValue, yValue)
var descriptionOfPoint: String = ""
switch point {
case (0, 0):
descriptionOfPoint = "該點為原點"
case (0, _):
descriptionOfPoint = "該點在 Y 軸上"
case (_, 0):
descriptionOfPoint = "該點在 X 軸上"
case let (x, y) where x == -y: // Value Bindings + where clause
descriptionOfPoint = "該點在第四象限上"
case let (x, y): // Value Bindings
descriptionOfPoint = "該點(\(x),\(y))不在任何軸上"
}
print(descriptionOfPoint)
XCTAssertEqual(descriptionOfPoint, "該點(\(xValue),\(yValue))不在任何軸上")
}
func testStructureIsImmutable() {
struct S {
var aValue: Int?
}
var s1 = S()
s1.aValue = 1
var s2 = s1
s2.aValue = 2
XCTAssertEqual(1, s1.aValue)
}
func testClassIsMutable() {
class C {
var aValue: Int?
}
let c1 = C()
c1.aValue = 1
let c2 = c1
c2.aValue = 2
XCTAssertEqual(2, c1.aValue)
}
func testSimpleClosure() {
var result: String? = nil
let aSimpleClosure = { () -> Void in
result = "A Simple Closure."
}
aSimpleClosure()
XCTAssertEqual("A Simple Closure.", result)
}
func testSimplestClosure() {
var result: String? = nil
let aSimplestClosure = {
result = "A Simplest Closure."
}
aSimplestClosure()
XCTAssertEqual("A Simplest Closure.", result)
}
func testClosureAsFunctionParameter() {
func setResult(_ aClosure: ()->Void) {
aClosure()
}
var result: String? = nil
let aSimplestClosure = {
result = "A Simplest Closure."
}
setResult(aSimplestClosure)
XCTAssertEqual("A Simplest Closure.", result)
}
func testClosureAsReturnType() {
func chineseToEnglish(word: String) -> String {
if word == "您好" {
return "Hello"
}
return "無法翻譯"
}
func chineseToNihongo(word: String) -> String {
if word == "您好" {
return "こんちは"
}
return "無法翻譯"
}
func getTranslator(from: String, to: String) -> ((String) -> String) {
if from == "中" && to == "英" {
return chineseToEnglish
} else if from == "中" && to == "日" {
return chineseToNihongo
}
return {(String) -> String in return "無法翻譯"}
}
let translator = getTranslator(from: "中", to: "英")
XCTAssertTrue(translator("您好") == "Hello")
XCTAssertTrue(translator("大家好") == "無法翻譯")
}
func testTrailingClosure() {
func executeClosure(_ closure: () -> String) -> String {
return closure()
}
let result = executeClosure() {
return "Hello"
}
XCTAssertEqual("Hello", result)
}
func testTailingClousre2() {
func anotherFunction(_ arg1: String, _ arg2: ()-> String) -> String{
return "\(arg1), \(arg2())"
}
XCTAssertEqual ("Hello, World", anotherFunction("Hello") { return "World" })
}
func testKeepArgs() {
var args: [String] = [String]()
func aFunction(_ arg: String) {
args.append(arg)
}
aFunction("Hello")
XCTAssertEqual(1, args.count)
}
func testKeepClosures() {
var closures: [()->String] = [()->String]()
func aFunction(_ closure: @escaping ()->String) {
closures.append(closure)
}
aFunction() {
return "Hello."
}
XCTAssertEqual("Hello.", closures.first!())
}
func testAutoClosure() {
var steps = [String]()
func readFile(_ filename: String) -> String {
steps.append("==> ①")
return "hello"
}
func aFunctionIncludeAutoClosure(filename: String, fileContent: @autoclosure () -> String) {
steps.append("==> ②")
if filename != "" {
steps.append("==> ③")
XCTAssertEqual("hello", fileContent())
}
}
steps.append("==> ④")
let filename = "aFile.txt"
aFunctionIncludeAutoClosure(filename: filename, fileContent: readFile(filename))
XCTAssertEqual(steps, ["==> ④", "==> ②", "==> ③", "==> ①"])
}
func testCommonFunction() {
func greet(myFriend person: String) -> String {
return "Hello, \(person)"
}
XCTAssertTrue(greet(myFriend: "Tom") == "Hello, Tom")
}
func testFunctionUseArgNameAsLabel() {
func greet(person: String) -> String {
return "Hello, \(person)"
}
XCTAssertTrue(greet(person: "Tom") == "Hello, Tom")
}
func testFunctionIgnoreLabel() {
func greet(_ person: String) -> String {
return "Hello, \(person)"
}
XCTAssertTrue(greet("Tom") == "Hello, Tom")
}
func testFunctionHasDefaultParameterValues() {
func welcome(name: String = "Guest") -> String {
return "Hello, \(name)."
}
XCTAssertEqual("Hello, Guest.", welcome())
}
func testVariadicParameters() {
func addTotal(_ numbers: Int...) -> Int {
var total: Int = 0
for number in numbers {
total += number
}
return total
}
XCTAssertEqual(10, addTotal(2, 3, 4, 1))
}
func testInOutParameters() {
func swap(number1: inout Int, number2: inout Int) {
let tempNumber = number1
number1 = number2
number2 = tempNumber
}
var n1 = 5, n2 = 3
swap(number1: &n1, number2: &n2)
XCTAssertEqual(3, n1)
XCTAssertEqual(5, n2)
}
func testDiscardableResultMethod() {
@discardableResult
func aMethod() -> String {
return "hello."
}
aMethod() // 若沒有加上 @discardableResult 會出現告警:Result of call to 'aMethod()' is unused.
}
func testDefer() {
var aNumber = 0
func aFunction() {
defer {
aNumber = 0
}
aNumber = 1
aNumber = 2
XCTAssertEqual(2, aNumber)
}
aFunction()
XCTAssertEqual(0, aNumber)
}
func testInitializerWithoutInheritance() {
class A {
var result: String = "a"
init(newResult: String) { // 指定建構子
self.result = newResult // 由於 A 不為任何類的子類,所以不需要呼叫 super。
}
convenience init() { // 便利建構子
self.init(newResult: "") // 便利建構子呼叫指定建構子
}
required init(aBool: Bool) {}
}
let a = A() // 以便利建構子生成 A 的實例
XCTAssertEqual("", a.result)
}
func testInitializerWithInheritance() {
class A {
var result: String = "a"
init(newResult: String) {
self.result = newResult
}
convenience init() {
self.init(newResult: "")
}
required init(aBool: Bool) {}
}
class B: A {
var number: Int?
// 繼承自父類的建構子
override init(newResult: String) {
super.init(newResult: "結果: \(newResult)")
}
// 可失敗建構子 (Failable Initializer)
init?(number: Int?) {
super.init(newResult: "b")
if number == nil { return nil }
self.number = number
}
// 便利建構子的覆寫不需要宣告 override
// 便利建構子不會被繼承
convenience init() {
self.init(newResult: "b")
}
// 由於父類 (A) 有宣告此建構A子,子類必須也加上
required init(aBool: Bool) {
super.init(aBool: aBool)
}
}
let b = B()
XCTAssertEqual("結果: b", b.result)
XCTAssertNil(B(number: nil))
}
func testDeInitializer() {
class A {
var aProperty: String = ""
}
class B {
var aAInstance: A = A()
deinit {
aAInstance.aProperty = "B is over."
}
}
var b = B()
let a = b.aAInstance
XCTAssertEqual("", a.aProperty)
b = B() // 取代舊的 B 實例
XCTAssertEqual("B is over.", a.aProperty)
}
func testReferenceDeadLock() {
class Book {
var author: Author?
}
class Author {
var book: Book?
}
var aBook: Book? = Book()
let aAuthor: Author? = Author()
aBook!.author = aAuthor
aAuthor!.book = aBook
aBook = nil
XCTAssertNotNil(aAuthor!.book)
}
func testWeakReference() {
class Book {
var author: Author?
}
class Author {
weak var book: Book?
}
var aBook: Book? = Book()
let aAuthor: Author? = Author()
aBook!.author = aAuthor
aAuthor!.book = aBook
aBook = nil
XCTAssertNil(aAuthor!.book)
}
func testLazyStoredProperties() {
class Animal {
lazy var isLive: Bool = true // 在特性前加上 lazy 關鍵字
var isHappy: Bool = true
}
let animal = Animal()
// 為了能夠檢查在記憶體裡的狀況,這裡需使用 Swift 的反射 (reflect) 語法
let mirror = Mirror(reflecting: animal)
// 取出物件的第一個特性,先證明為 isLive 特性
XCTAssertEqual("isLive.storage", mirror.children.first?.label)
// 並證明其值仍為 nil,還沒被設定為 true
XCTAssertEqual("nil", String(describing: (mirror.children.first?.value)!))
// 取出物件的另一個特性,應該是 isHappy,並證明其值已經被設定為 true
XCTAssertEqual("true",
String(describing: (mirror.children[mirror.children.index(after: mirror.children.startIndex)].value)))
// 取用 isLive 特性
let _ = animal.isLive
// 取出物件的第一個特性,先證明為 isLive 特性
XCTAssertEqual("isLive.storage", mirror.children.first?.label)
// 並證明其值被設定為 true (為 optional 型別)
XCTAssertEqual("Optional(true)",
String(describing: (mirror.children.first?.value)!))
}
func testTypePropertiesAndMethods() {
class Util {
static var inch: Float = 0.0
static func centWith() -> Float {
return inch * 2.54
}
static func centWith(inch: Float) -> Float {
return inch * 2.54
}
}
Util.inch = 2
XCTAssertEqual(5.08, Util.centWith())
XCTAssertEqual(2.54, Util.centWith(inch: 1))
}
func testBoringExample() {
class SomeClass {
var someProperty: String = ""
func getSomeValue() -> String {
return "hello"
}
}
let aInstance = SomeClass()
aInstance.someProperty = aInstance.getSomeValue()
XCTAssertEqual("hello", aInstance.someProperty)
}
func testAssignClosureResultToProperty() {
class SomeClass {
let someProperty: String = {
return "some value"
}()
}
XCTAssertEqual("some value", SomeClass().someProperty)
}
func testAssignInstanceProperty() {
class SomeClassForProperty: NSObject {
override var description: String {
return "some value"
}
}
class SomeClass {
let someProperty: String = SomeClassForProperty().description
}
XCTAssertEqual("some value", SomeClass().someProperty)
}
func testExtension() {
XCTAssertEqual("Hello".toChinese(), "您好")
}
func testExtensionImplementProtocol() {
XCTAssertEqual("Hello".sayFrenchHello(), "Bonjour")
}
func testOptionalProtocol() {
class SomeClass: AOptionalProtocol {}
XCTAssertNotNil(SomeClass())
}
func testClassOnlyProtocols() {
class SomeClass: SomeClassProtocol {}
/*
由於 SomeClassProtocol 是繼承自 AnyObject 這個協定,
所以無法使用下列代碼讓結構/列舉宣告實作 SomeClassProtocol。
struct SomeStructure: SomeClassProtocol {}
enum SomeEnum: SomeClassProtocol {}
錯誤訊息如下:
Non-class type 'SomeStructure'
cannot conform to class protocol 'SomeClassProtocol'
*/
}
func testSeveralTypesEnum() {
enum Emotion {
case happy, sad
case laugh()
case eat(foodName: String) /* Associated Values */
func brief() -> String {
switch self {
case .eat(foodName: let fName):
return "有些人心情不好會大吃\(fName)一頓"
default:
return ""
}
}
}
let eatEmotion: Emotion = Emotion.eat(foodName: "牛排")
XCTAssertEqual(eatEmotion.brief(), "有些人心情不好會大吃牛排一頓")
}
func testEnumRawValue() {
enum Season: Int {
case Spring, Summer, Fall, Winter
}
XCTAssertEqual(Season(rawValue: 1), Season.Summer)
XCTAssertEqual(Season(rawValue: 3), Season.Winter)
}
func testEnumOfCustomRawValue() {
enum Swith: Int {
case ON = 1, OFF = 0
}
XCTAssertEqual(Swith(rawValue: 1), Swith.ON)
}
func testGenerics() {
func add<Item>(item1: Item, item2: Item) -> Any {
if item1 is Int {
return (item1 as! Int) + (item2 as! Int)
}
if item1 is Double {
return (item1 as! Double) + (item2 as! Double)
}
if item1 is String {
return "\(item1)\(item2)"
}
return EMPTY
}
XCTAssertEqual(2, add(item1: 1, item2: 1) as! Int)
XCTAssertEqual(2.5, add(item1: 0.5, item2: 2) as! Double)
XCTAssertEqual("11", add(item1: "1", item2: "1") as! String)
}
func testErroHandler() {
enum RequestError: Error {
case wrongFormat
case deadNetwork
func simpleDescription() -> String {
if self == RequestError.wrongFormat {
return "wrong format"
}
if self == RequestError.deadNetwork {
return "dead network"
}
return "unknown"
}
}
func checkNetworkAvailable() -> Bool {
return true
}
func request(parameter: Dictionary<String, String>?) throws -> (String, String) {
if parameter == nil || parameter?.keys.count == 0 {
throw RequestError.wrongFormat
}
if !checkNetworkAvailable() {
throw RequestError.deadNetwork
}
return ("200", "OK")
}
XCTAssertThrowsError(try request(parameter: Dictionary<String, String>()),
"Parameter dictionary is empty") { (error) in
XCTAssertTrue(error is RequestError)
}
var errorReason: String? = nil
do {
let response = try request(parameter: Dictionary<String, String>())
print(response)
} catch RequestError.wrongFormat {
errorReason = RequestError.wrongFormat.simpleDescription()
} catch RequestError.deadNetwork {
errorReason = RequestError.deadNetwork.simpleDescription()
} catch {
errorReason = "Unknown"
}
XCTAssertEqual("wrong format", errorReason)
let response = try? request(parameter: Dictionary<String, String>())
XCTAssertNil(response)
}
func testIf() {
let number1 = 10
let number2 = 9
let number3 = 8
var result = 0
/* 以下三個例子是同義的 */
if number1 > number2 {
if number2 > number3 {
result += 1
}
}
if (number1 > number2) && (number2 > number3) {
result += 1
}
if number1 > number2, number2 > number3 {
result += 1
}
XCTAssertEqual(3, result)
if (number1 < number2) || (number2 > number3) {
result += 1
}
XCTAssertEqual(4, result)
}
func testNilCoalescingOperator() {
var aInt: Int?
aInt = Int("1")
XCTAssertEqual(1, aInt ?? 0)
aInt = Int("a")
XCTAssertEqual(0, aInt ?? 0)
}
func testTernaryConditionalOperator() {
let score = 65
XCTAssertEqual("考試通過", ((score >= 60) ? "考試通過" : "考試不及格"))
}
func testClosedRange() {
var result:Int = 0
for number in 1...10 {
result += number
}
XCTAssertEqual(55, result)
}
func testHalfOpenRange() {
var result:Int = 0
for number in 1..<11 {
result += number
}
XCTAssertEqual(55, result)
}
func testMultilineString() {
let articleTexts = """
歡迎一起來學習 Swift "最新版"!
Swift 是蘋果官方發佈的程式語言。
"""
XCTAssertNotEqual("歡迎一起來學習 Swift \"最新版\"!Swift 是蘋果官方發佈的程式語言。", articleTexts)
XCTAssertEqual("歡迎一起來學習 Swift \"最新版\"!\nSwift 是蘋果官方發佈的程式語言。", articleTexts)
}
func testSpecialCharacters() {
let blackHeart = "\u{2665}"
XCTAssertEqual(blackHeart, "♥")
}
func testGetFirstCharacterFromString() {
let greeting = "您好,有什麼能為您服務的?"
XCTAssertEqual("您", greeting[greeting.startIndex])
}
func testCountStringLength() {
let greeting = "您好,有什麼能為您服務的?"
XCTAssertEqual(greeting.count, greeting.endIndex.encodedOffset)
}
func testSubStringWithBefore() {
let greeting = "您好,有什麼能為您服務的?"
XCTAssertEqual("?", greeting[greeting.index(before: greeting.endIndex)])
}
func testFromIntToStringIndex() {
let greeting = "您好,有什麼能為您服務的?"
XCTAssertEqual("?", greeting[greeting.index(before: String.Index(encodedOffset: greeting.count))])
}
func testGetIndexPositonOfCharacter() {
let greeting = "您好,有什麼能為您服務的?"
let indexOfComma = greeting.index(of: ",")
XCTAssertEqual(indexOfComma, String.Index(encodedOffset: 2))
}
func testStringReverse() {
let greeting = "您好,有什麼能為您服務的?"
XCTAssertEqual("?的務服您為能麼什有,好您", String(greeting.reversed()))
}
func testStringInsert() {
var welcome = "hello"
// 插入字元
welcome.insert(",", at: welcome.endIndex)
XCTAssertEqual("hello,", welcome)
// 插入字串
welcome.insert(contentsOf: " world.", at: welcome.endIndex)
XCTAssertEqual("hello, world.", welcome)
}
func testStringRemove() {
var welcome = "hello, world."
welcome.remove(at: welcome.index(before: welcome.endIndex))
XCTAssertEqual("hello, world", welcome)
welcome.removeSubrange(
welcome.index(welcome.endIndex, offsetBy: -(", world".count))
..<
welcome.endIndex)
XCTAssertEqual("hello", welcome)
}
}
protocol LearningLanguage {
var languageName: String {get set}
var description: String {get set}
func recite()
}
protocol LearningLanguageWithMutaingKeyword {
var languageName: String {get set}
var description: String {get set}
mutating func recite()
}
@objc protocol AOptionalProtocol {
@objc optional func aOptionalMethod()
}
extension String {
func toChinese() -> String {
if self == "Hello" {
return "您好"
}
return "Unknown"
}
}
protocol LearningFrench {
func sayFrenchHello() -> String
}
extension String: LearningFrench {
func sayFrenchHello() -> String {
if self == "Hello" {
return "Bonjour"
}
return "Unknown"
}
}
protocol SomeClassProtocol: AnyObject {} // AnyObject 為 protocol
class JustForGenerics: XCTestCase {
func testTypeConstraintGenerics() {
func add<Item: Addable>(item1: Item, item2: Item) -> Item {
return item1 + item2
}
XCTAssertEqual(2, add(item1: 1, item2: 1))
XCTAssertEqual("11", add(item1: "1", item2: "1"))
}
}
protocol Addable {
static func +(lItem: Self, rItem: Self) -> Self
}
extension Int: Addable {}
extension String: Addable {
static func +(lItem: String, rItem: String) -> String {
return "\(lItem)\(rItem)"
}
}
view rawSwift4.swift hosted with ❤ by GitHub
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment