Change license to AGPL
This commit:
- Updates the `LICENSE` file
- Start every file with something like:
// Copyright YEAR_FIRST_PUBLISHED Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
---
First, I removed existing license headers with this Ruby 3.1.2 script:
require 'set'
EXTENSIONS_TO_CHECK = Set['.h', '.hpp', '.cpp', '.m', '.mm', '.pch', '.swift']
same = 0
different = 0
all_files = `git ls-files`.lines.map { |line| line.strip }
all_files.each do |relative_path|
if relative_path == 'Pods'
next
end
unless EXTENSIONS_TO_CHECK.include? File.extname(relative_path)
next
end
path = File.expand_path(relative_path)
contents = File.read(path)
new_contents = contents.sub(/\/\/\n\/\/ Copyright .*\n\/\/\n\n/, '')
if contents == new_contents
same += 1
else
different += 1
end
File.write(path, new_contents)
end
puts "updated #{different} file(s), left #{same} untouched"
I'm sure this script could be improved, but it worked well enough.
Then, I created `Scripts/lint/lint-license-headers` and ran it to auto-
fix a lot of files. This changed the mode of some files, but I think
that's actually desirable. For example,
`SignalServiceKit/src/Util/AppContext.m` previously had a mode of
`0755/-rwxr-xr-x`, and it's now `0644/-rw-r--r--`.
Then I fixed some stragglers and updated the precommit script.
See [a similar change in the Desktop app][0].
[0]: 8bfaf598af
232 lines
5.9 KiB
Swift
232 lines
5.9 KiB
Swift
//
|
|
// Copyright 2020 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
import Foundation
|
|
import XCTest
|
|
|
|
@testable import SignalServiceKit
|
|
|
|
class UnfairLockTest: SSKBaseTestSwift {
|
|
|
|
private var dut: UnfairLock! = nil
|
|
|
|
override func setUp() {
|
|
dut = UnfairLock()
|
|
}
|
|
|
|
// MARK: - Lock + Unlock
|
|
func testSimpleLockAndUnlock() {
|
|
// Setup
|
|
var sharedVal = 0
|
|
|
|
// Test
|
|
fanout(1000) {
|
|
self.dut.lock()
|
|
sharedVal += 1
|
|
self.dut.unlock()
|
|
}
|
|
|
|
// Verify
|
|
XCTAssertEqual(sharedVal, 1000, "Lock failed to prevent data race.")
|
|
}
|
|
|
|
func testLockedClosure() {
|
|
// Setup
|
|
var sharedVal = 0
|
|
|
|
// Test
|
|
fanout(1000) {
|
|
self.dut.withLock {
|
|
sharedVal += 1
|
|
}
|
|
}
|
|
|
|
// Verify
|
|
XCTAssertEqual(sharedVal, 1000, "Lock failed to prevent data race.")
|
|
}
|
|
|
|
// MARK: - Lock attempts
|
|
|
|
func testTryLock_guaranteedFailure() {
|
|
// Setup
|
|
let didLockOuter = dut.tryLock()
|
|
var didLockInner = false
|
|
|
|
// Test
|
|
fanout(1000) {
|
|
if self.dut.tryLock() {
|
|
didLockInner = true
|
|
self.dut.unlock()
|
|
}
|
|
}
|
|
dut.unlock()
|
|
|
|
// Verify
|
|
XCTAssertTrue(didLockOuter, "Failed to acquire the uncontended lock.")
|
|
XCTAssertFalse(didLockInner, "tryLock() acquired an already acquired lock.")
|
|
}
|
|
|
|
func testTryLock_contended() {
|
|
// Setup
|
|
var blockInvocationCount = 0
|
|
|
|
// Test
|
|
fanout(1000) {
|
|
guard self.dut.tryLock() else { return }
|
|
blockInvocationCount += 1
|
|
self.dut.unlock()
|
|
}
|
|
|
|
// Verify
|
|
XCTAssertGreaterThanOrEqual(blockInvocationCount, 1, "Invalid invocation count. Expected: [1, 1000]")
|
|
XCTAssertLessThanOrEqual(blockInvocationCount, 1000, "Invalid invocation count. Expected: [1, 1000]")
|
|
}
|
|
|
|
func testTryLockClosure_guaranteedFailure() {
|
|
// Setup
|
|
let didLockOuter = dut.tryLock()
|
|
var didLockInner = false
|
|
|
|
// Test
|
|
fanout(1000) {
|
|
didLockInner = didLockInner || self.dut.tryWithLock {
|
|
didLockInner = true
|
|
}
|
|
}
|
|
dut.unlock()
|
|
|
|
// Verify
|
|
XCTAssertTrue(didLockOuter, "Failed to acquire the uncontended lock.")
|
|
XCTAssertFalse(didLockInner, "tryLock() acquired an already acquired lock.")
|
|
}
|
|
|
|
func testTryLockClosure_contended() {
|
|
// Setup
|
|
var blockInvocationCount = 0
|
|
|
|
// Test
|
|
fanout(1000) {
|
|
var invokedLocally = false
|
|
let success = self.dut.tryWithLock {
|
|
blockInvocationCount += 1
|
|
|
|
// To catch any repeat invocations of the closure
|
|
XCTAssertFalse(invokedLocally)
|
|
invokedLocally = true
|
|
}
|
|
// If the lock was acquired, the closure should have run
|
|
XCTAssertEqual(invokedLocally, success)
|
|
}
|
|
|
|
// Verify
|
|
XCTAssertGreaterThanOrEqual(blockInvocationCount, 1, "Invalid invocation count. Expected: [1, 1000]")
|
|
XCTAssertLessThanOrEqual(blockInvocationCount, 1000, "Invalid invocation count. Expected: [1, 1000]")
|
|
}
|
|
|
|
func testPropagatedReturnValue() {
|
|
// Setup
|
|
let outerVal: String? = "Hello, this is an optional string"
|
|
|
|
// Test
|
|
let returnedVal = dut.withLock {
|
|
return outerVal?.appending("!")
|
|
}
|
|
|
|
// Expect
|
|
XCTAssertEqual(returnedVal, "Hello, this is an optional string!")
|
|
}
|
|
|
|
func testPropagatedReturnValue_tryLockSuccess() {
|
|
// Setup
|
|
let outerVal: String? = "Hello, this is an optional string"
|
|
|
|
// Test
|
|
let returnedVal: String?? = dut.tryWithLock {
|
|
return outerVal?.appending("!")
|
|
}
|
|
|
|
// Expect
|
|
XCTAssertEqual(returnedVal, "Hello, this is an optional string!")
|
|
}
|
|
|
|
func testPropagatedReturnValue_tryLockFailure() {
|
|
// Setup
|
|
let outerVal: String? = "Hello, this is an optional string"
|
|
|
|
// Test
|
|
let returnedVal: String?? = dut.tryWithLock {
|
|
return dut.tryWithLock {
|
|
return outerVal?.appending("!")
|
|
} ?? "oops nevermind"
|
|
}
|
|
|
|
// Expect
|
|
XCTAssertEqual(returnedVal, "oops nevermind")
|
|
}
|
|
|
|
// MARK: - Throwing Inner Closure
|
|
|
|
func testThrowingLockedClosure() {
|
|
// Setup
|
|
var didAcquireLock = false
|
|
var didCatchError = false
|
|
var didReacquireLock = false
|
|
|
|
// Test
|
|
let toThrow = NSError(domain: "UnfairLockTests", code: 2, userInfo: nil)
|
|
do {
|
|
try dut.withLock {
|
|
didAcquireLock = true
|
|
throw toThrow
|
|
}
|
|
} catch {
|
|
XCTAssertEqual(toThrow, (error as NSError))
|
|
didCatchError = true
|
|
}
|
|
|
|
dut.withLock {
|
|
didReacquireLock = true
|
|
}
|
|
|
|
// Verify
|
|
XCTAssertTrue(didAcquireLock)
|
|
XCTAssertTrue(didCatchError)
|
|
XCTAssertTrue(didReacquireLock)
|
|
}
|
|
|
|
func testThrowingTryLockedClosure() {
|
|
// Setup
|
|
var didAcquireLock = false
|
|
var didCatchError = false
|
|
var didReacquireLock = false
|
|
|
|
// Test
|
|
let toThrow = NSError(domain: "UnfairLockTests", code: 2, userInfo: nil)
|
|
do {
|
|
try dut.tryWithLock {
|
|
didAcquireLock = true
|
|
throw toThrow
|
|
}
|
|
} catch {
|
|
XCTAssertEqual(toThrow, (error as NSError))
|
|
didCatchError = true
|
|
}
|
|
|
|
didReacquireLock = dut.tryWithLock {}
|
|
|
|
// Verify
|
|
XCTAssertTrue(didAcquireLock)
|
|
XCTAssertTrue(didCatchError)
|
|
XCTAssertTrue(didReacquireLock)
|
|
}
|
|
|
|
// MARK: - Test Helpers
|
|
|
|
func fanout(_ iterations: Int, _ block: () -> Void) {
|
|
DispatchQueue.concurrentPerform(iterations: iterations) { (_) in block() }
|
|
}
|
|
|
|
}
|