Problems
JSON parser, returns custom error type in case of failures.
typealias JSON = [String: Any]
enum ParsingError: Error {
case invalidInput
case internalError(Error)
}
func parse(string: String) throws -> JSON ...
do {
let string = "{\"name\": \"John\", \"age\": 30}"
let result = try parse(string: string)
XCTAssertEqual(result["name"] as? String, "John")
XCTAssertEqual(result["age"] as? Int, 30)
} catch {
XCTFail()
}
do {
let string = "{invalid{json"
_ = try parse(string: string)
} catch {
XCTAssertTrue(error is ParsingError)
}
- 0.66 Compiled
- 0.64 Passed Solutions
HTML generator from predefined elements tree.
Output with standart HTML like this "<div><a href="swifteval"></a></div>"
indirect enum HTMLNode {
case text(_ content: String)
case element(_ name: String, attributes: [String : String] = [:], children: [Self] = [])
}
func generate(_ tree: HTMLNode) -> String ...
class HTMLDescriptor: NSObject, XMLParserDelegate {
func describe(_ html: String) -> String {
guard let data = html.data(using: .utf8) else {
return ""
}
var output = ""
let delegate = Delegate(output: &output)
let parser = XMLParser(data: data)
parser.delegate = delegate
parser.parse()
return output
}
class Delegate: NSObject, XMLParserDelegate {
var outputRef: UnsafeMutablePointer<String>
init(output: UnsafeMutablePointer<String>) {
self.outputRef = output
}
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String: String]) {
outputRef.pointee += "Start: \(elementName) \(attributeDict)"
outputRef.pointee += "\n"
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
outputRef.pointee += "Content: \(string)"
outputRef.pointee += "\n"
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
outputRef.pointee += "End: \(elementName)"
outputRef.pointee += "\n"
}
}
}
let generated = generate(.element("div", children: [
.element("a", attributes: ["href": "swifteval"]),
.element("p", attributes: ["style": "color:red;"], children: [.text("Hello, SwiftEval!")]),
.element("ul", attributes: [:], children: (0...3).map(String.init).map({ .element("li", attributes: [:], children: [.text($0)]) }))
]))
let descriptor = HTMLDescriptor()
let expected = descriptor.describe(#"<div><a href="swifteval"></a><p style="color:red;">Hello, SwiftEval!</p><ul><li>0</li><li>1</li><li>2</li><li>3</li></ul></div>"#)
let received = descriptor.describe(generated)
XCTAssertEqual(expected, received)
- 0.77 Compiled
- 0.69 Passed Solutions
Calculator which supports operations from readable string format.
Valid tokens is "+-*/()", example input is "2+2*2".
enum CalculateError: Error {
case invalidInput
}
func calculate(_ string: String) throws -> Double ...
XCTAssertEqual(try calculate("2+2"), 4.0)
XCTAssertEqual(try calculate("2+2*2"), 6.0)
XCTAssertEqual(try calculate("(2+2)*2"), 8.0)
XCTAssertThrowsError(try calculate("A/B"))
- 0.36 Compiled
- 0.08 Passed Solutions
Function to execute binary with arguments.
Returns tuple where first element is stdout and second is stderr.
func execute(binary: String, arguments: [String]) -> (String, String) ...
var (stdout, stderr) = execute(binary: "/bin/zsh", arguments: ["-c", "echo Hello!"])
XCTAssertEqual(stdout.trimmingCharacters(in: .whitespacesAndNewlines), "Hello!")
XCTAssertEqual(stderr.trimmingCharacters(in: .whitespacesAndNewlines), "")
(stdout, stderr) = execute(binary: "/usr/bin/xcodebuild", arguments: ["-version"])
XCTAssertTrue(stdout.contains("Build version"))
(stdout, stderr) = execute(binary: "/usr/bin/xcodebuild", arguments: ["version"])
XCTAssertTrue(stderr.contains("Unknown build action"))
- 0.55 Compiled
- 0.35 Passed Solutions
Memoization function that caches the results of expensive computations.
func memoize<T: Hashable, U>(_ function: @escaping (T) -> U) -> (T) -> U ...
var callCount = 0
let factorial: (Int) -> Int = { n in
callCount += 1
return (1...n).reduce(1, *)
}
let memoizedFactorial = memoize(factorial)
XCTAssertEqual(memoizedFactorial(5), 120)
XCTAssertEqual(memoizedFactorial(5), 120)
XCTAssertEqual(callCount, 1) // Should only call factorial once for the same input
XCTAssertEqual(memoizedFactorial(6), 720)
XCTAssertEqual(callCount, 2) // Call count should increase only for new input
- 0.87 Compiled
- 0.87 Passed Solutions
Retry mechanism that retries a task a specified number of times before failing.
func retry<T>(attempts: Int, task: @escaping () throws -> T) throws -> T ...
var attempts = 0
let result: String = try retry(attempts: 3) {
attempts += 1
if attempts < 3 {
throw NSError(domain: "TestError", code: 1, userInfo: nil)
}
return "Success"
}
XCTAssertEqual(result, "Success")
XCTAssertEqual(attempts, 3)
- 0.49 Compiled
- 0.47 Passed Solutions
Simple dependency injection (DI) container.
protocol DIContainerProtocol {
func register<T>(_ type: T.Type, factory: @escaping () -> T)
func resolve<T>(_ type: T.Type) -> T?
}
class DIContainer: ...
let container = DIContainer()
container.register(String.self) { "Hello, World!" }
container.register(Int.self) { 42 }
let string: String? = container.resolve(String.self)
let integer: Int? = container.resolve(Int.self)
XCTAssertEqual(string, "Hello, World!")
XCTAssertEqual(integer, 42)
let nonExistent: Double? = container.resolve(Double.self)
XCTAssertNil(nonExistent)
- 0.68 Compiled
- 0.61 Passed Solutions
Finite state machine with possibility to register custom transitions between states.
protocol StateMachineProtocol {
associatedtype State: Hashable
associatedtype Event: Hashable
init(state: State)
var state: State { get }
func trigger(event: Event)
func registerTransition(from: State, to: State, event: Event)
}
class StateMachine< ...
enum TrafficLightState: Hashable {
case red, green, yellow
}
enum TrafficLightEvent: Hashable {
case timer
}
let stateMachine = StateMachine<TrafficLightState, TrafficLightEvent>(state: .green)
stateMachine.registerTransition(from: .red, to: .green, event: .timer)
stateMachine.registerTransition(from: .green, to: .yellow, event: .timer)
stateMachine.registerTransition(from: .yellow, to: .red, event: .timer)
XCTAssertEqual(stateMachine.state, .green)
stateMachine.trigger(event: .timer)
XCTAssertEqual(stateMachine.state, .yellow)
stateMachine.trigger(event: .timer)
XCTAssertEqual(stateMachine.state, .red)
stateMachine.trigger(event: .timer)
XCTAssertEqual(stateMachine.state, .green)
- 0.23 Compiled
- 0.22 Passed Solutions
Abstract file system manager and metadata calculation.
Used to calculate total size of all files in file system, files count and file system tree depth.
indirect enum FileSystemNode {
case file(name: String, size: Int)
case directory(name: String, contents: [FileSystemNode])
}
protocol FileSystemInfo {
var totalSize: Int { get }
var filesCount: Int { get }
var treeDepth: Int { get }
}
extension FileSystemNode: FileSystemInfo { ...
let file = FileSystemNode.file(name: "file.txt", size: 100)
XCTAssertEqual(file.totalSize, 100)
let directory = FileSystemNode.directory(name: "directory", contents: [])
XCTAssertEqual(directory.totalSize, 0)
XCTAssertEqual(directory.treeDepth, 1)
let system = FileSystemNode.directory(name: "directory", contents: [ // 1
FileSystemNode.file(name: "file.txt", size: 100),
FileSystemNode.directory(name: "sub_directory", contents: [ // 2
FileSystemNode.directory(name: "sub_sub_directory", contents: [ // 3
FileSystemNode.file(name: "image.png", size: 200), // 4
FileSystemNode.file(name: "audio.aac", size: 500) // 4
])
])
])
XCTAssertEqual(system.totalSize, 800)
XCTAssertEqual(system.treeDepth, 4)
- 0.43 Compiled
- 0.25 Passed Solutions
Generic stack with push and pop functions.
protocol StackProtocol {
associatedtype Element
init()
func push(_ element: Element)
func pop() -> Element?
}
class Stack< ...
var stack = Stack<Int>()
stack.push(1)
stack.push(2)
XCTAssertEqual(stack.pop(), 2)
XCTAssertEqual(stack.pop(), 1)
XCTAssertNil(stack.pop())
- 0.26 Compiled
- 0.25 Passed Solutions
Generic in-memory cache that follows to the LRU (Least Recently Used) eviction policy.
The cache should have a specified capacity limit, and when this limit is reached, it should remove the least recently used item to make space for new entries.
protocol CacheProtocol {
associatedtype Key: Hashable
associatedtype Element
init(capacity: Int)
subscript(key: Key) -> Element? { get set }
}
class Cache<Key ...
let cache = Cache<String, Int>(capacity: 2)
cache["a"] = 1
cache["b"] = 2
cache["c"] = 3 // This should evict key "a"
XCTAssertNil(cache["a"])
XCTAssertEqual(cache["b"], 2)
XCTAssertEqual(cache["c"], 3)
- 0.26 Compiled
- 0.25 Passed Solutions
Caching mechanism with expiration eviction policy.
Subscript methods used for convenient access.
protocol ExpirableCacheProtocol {
associatedtype Key: Hashable
associatedtype Value
func put(value: Value, key: Key, expiration: TimeInterval)
func get(key: Key) -> Value?
}
class ExpirableCache< ...
let cache = ExpirableCache<String, String>()
cache.put(value: "Hello, SwiftEval!", key: "greeting", expiration: 1.0)
Thread.sleep(forTimeInterval: 1.1)
XCTAssertNil(cache.get(key: "greeting"))
cache.put(value: "Hello, SwiftEval!", key: "greeting", expiration: 1.0)
Thread.sleep(forTimeInterval: 0.9)
XCTAssertEqual(cache.get(key: "greeting"), "Hello, SwiftEval!")
- 0.49 Compiled
- 0.38 Passed Solutions
Simple XOR encryptor and decryptor that converts plain text into encrypted text by applying the binary 'Exclusive OR' operator implemented according to the protocol.
protocol EncryptorProtocol {
func encrypt(_ string: String, _ key: String) -> Data
func decrypt(_ data: Data, _ key: String) -> String
}
class Encryptor: EncryptorProtocol { ...
let key = "passphrase"
let encryptor = Encryptor()
let originalText = "Hello, SwiftEval!"
let encryptedData = encryptor.encrypt(originalText, key)
let encryptedText = String(data: encryptedData, encoding: .utf8)
let decryptedText = encryptor.decrypt(encryptedData, key)
XCTAssertEqual(originalText, decryptedText)
XCTAssertEqual(encryptedText, "8\u{04}\u{1F}\u{1F}\u{1F}DR2\u{04}\u{0C}\u{16}\u{15}6\u{05}\u{11}\u{04}S")
- 0.50 Compiled
- 0.43 Passed Solutions
Rate limiter that controls the rate of actions.
Consists with a maximum number of requests and a time interval, and includes a method to determine if a new request can be made within the defined limits.
protocol RateLimiterProtocol {
init(maxRequests: Int, timeInterval: TimeInterval)
func allowRequest() -> Bool
}
class RateLimiter: ...
let rateLimiter = RateLimiter(maxRequests: 3, timeInterval: 1)
XCTAssertTrue(rateLimiter.allowRequest())
XCTAssertTrue(rateLimiter.allowRequest())
XCTAssertTrue(rateLimiter.allowRequest())
XCTAssertFalse(rateLimiter.allowRequest())
Thread.sleep(forTimeInterval: 1)
XCTAssertTrue(rateLimiter.allowRequest())
- 0.38 Compiled
- 0.28 Passed Solutions
Basic number counter with possibility to increment counter and access current value.
Thread-safe for read and write operations.
protocol ThreadSafeCounterProtocol {
init(value: Int)
func increment()
func currentValue() -> Int
}
class ThreadSafeCounter: ThreadSafeCounterProtocol ...
let counter = ThreadSafeCounter(value: 0)
DispatchQueue.concurrentPerform(iterations: 1000) { _ in
counter.increment()
}
XCTAssertEqual(counter.currentValue(), 1000)
- 0.41 Compiled
- 0.41 Passed Solutions
Functional pipeline builder class conforming to a protocol, allowing chaining transformations with type changes.
Ensure the final output is produced by sequentially applying transformations starting from an initial value.
protocol PipelineProtocol {
associatedtype Output
init(value: Output)
func pipe<U>(_ transform: @escaping (Output) -> U) -> Pipeline<U>
func execute() -> Output
}
class Pipeline< ...
let expected = "Output is 12.0"
let received = Pipeline(value: "Hello!")
.pipe { $0.count }
.pipe { Double($0 * 2) }
.pipe { "Output is \($0)" }
.execute()
XCTAssertEqual(received, expected)
- 0.23 Compiled
- 0.21 Passed Solutions
Generic observable property that notifies observers of value changes.
protocol ObservablePropertyProtocol {
associatedtype Value
init(value: Value)
var value: Value { get set }
func subscribe(_ observer: @escaping (Value) -> Void) -> UUID
func unsubscribe(_ observer: UUID)
}
class ObservableProperty<Value> ...
let observable = ObservableProperty<Int>(value: 0)
var observedValue: Int?
let observer = observable.subscribe { newValue in
observedValue = newValue
}
observable.value = 10
XCTAssertEqual(observedValue, 10)
observable.value = 20
XCTAssertEqual(observedValue, 20)
observable.unsubscribe(observer)
observable.value = 30
XCTAssertEqual(observedValue, 20)
- 0.21 Compiled
- 0.20 Passed Solutions
Property wrapper that clamps value within a specified range.
protocol ClampedProtocol {
associatedtype Value: Comparable
init(wrappedValue: Value, _ range: ClosedRange<Value>)
}
@propertyWrapper
struct Clamped< ...
@Clamped(0...10) var value: Int = 0
value = 5
XCTAssertEqual(value, 5)
value = 15
XCTAssertEqual(value, 10)
value = -5
XCTAssertEqual(value, 0)
- 0.47 Compiled
- 0.37 Passed Solutions
Property wrapper that logs access and modification of the wrapped property.
enum Event {
case get, set
}
protocol LoggedProtocol {
associatedtype Value
init(wrappedValue: Value, logger: @escaping (Event, Value) -> Void)
}
@propertyWrapper
struct Logged< ...
var logs: [String] = []
let logger: (Event, Int) -> Void = {
switch $0 {
case .get:
logs.append("Accessing value: \($1)")
case .set:
logs.append("Setting value: \($1)")
}
}
@Logged(logger: logger) var value: Int = 0
_ = value
XCTAssertEqual(logs, ["Accessing value: 0"])
value = 10
XCTAssertEqual(logs, ["Accessing value: 0", "Setting value: 10"])
- 0.40 Compiled
- 0.27 Passed Solutions
Weather application provider.
Handle user actions to fill search bar results and use WeatherProvider to check forecast.
protocol WeatherProvider {
func forecast(for city: String) throws -> String
}
enum UserAction {
case keyboardCharacterSelect(Character)
case keyboardDeleteBackwards
case searchButtonPress
}
enum ApplicationFeedback: Equatable {
case success(city: String, forecast: String)
case failure(city: String)
}
protocol WeatherApplicationDependencies {
init(provider: WeatherProvider)
}
protocol WeatherApplicationInteractions {
func handle(action: UserAction) -> ApplicationFeedback?
}
typealias WeatherApplicationProtocol = WeatherApplicationDependencies & WeatherApplicationInteractions
class WeatherApplication: WeatherApplicationProtocol ...
enum WeatherProviderError: Error {
case notFound(city: String)
}
struct WeatherProviderImplementation: WeatherProvider {
func forecast(for city: String) throws -> String {
switch city {
case "Kyiv":
return "+28"
case "Warsaw":
return "+24"
default:
throw WeatherProviderError.notFound(city: city)
}
}
}
let provider = WeatherProviderImplementation()
let application = WeatherApplication(provider: provider)
XCTAssertNil(application.handle(action: .keyboardCharacterSelect("K")))
XCTAssertNil(application.handle(action: .keyboardCharacterSelect("y")))
XCTAssertNil(application.handle(action: .keyboardCharacterSelect("i")))
XCTAssertNil(application.handle(action: .keyboardCharacterSelect("v")))
XCTAssertEqual(application.handle(action: .searchButtonPress), .success(city: "Kyiv", forecast: "+28"))
(0..<4).forEach { _ in _ = application.handle(action: .keyboardDeleteBackwards) } // Clear search input
XCTAssertNil(application.handle(action: .keyboardCharacterSelect("W")))
XCTAssertNil(application.handle(action: .keyboardCharacterSelect("s")))
XCTAssertNil(application.handle(action: .keyboardCharacterSelect("a")))
XCTAssertNil(application.handle(action: .keyboardCharacterSelect("w")))
XCTAssertEqual(application.handle(action: .searchButtonPress), .failure(city: "Wsaw"))
- 0.41 Compiled
- 0.32 Passed Solutions
Thread-safe bank account class using an actor that allows asynchronous deposits and withdrawals, ensuring that the account balance remains consistent and transactions are atomic.
protocol BankAccountProtocol {
init(balance: Double)
var balance: Double { get async }
func deposit(amount: Double) async
func withdraw(amount: Double) async -> Bool
}
actor BankAccount: BankAccountProtocol { ...
let account = BankAccount(balance: 1000.0)
let iterations = 1000
await withTaskGroup(of: Void.self) { group in
for _ in 0..<iterations {
group.addTask {
await account.deposit(amount: 1.0)
}
}
for _ in 0..<iterations {
group.addTask {
let _ = await account.withdraw(amount: 1.0)
}
}
}
let balance = await account.balance
XCTAssertEqual(balance, 1000.0)
let withdrawAllowed = await account.withdraw(amount: 1100.0)
XCTAssertFalse(withdrawAllowed)
let finalBalance = await account.balance
XCTAssertEqual(finalBalance, 1000.0)
- 0.28 Compiled
- 0.26 Passed Solutions
Property wrapper that caches the computed value of a property and recomputes it only when a specified condition changes.
protocol CachedProperty {
associatedtype Value
init(wrappedValue: @autoclosure @escaping () -> Value, condition: @escaping () -> Bool)
}
@propertyWrapper
struct Cached<Value>: CachedProperty { ...
var value = 0
var condition = false
var computationCount = 0
@Cached(condition: { condition })
var cached: Int = {
value += 1
computationCount += 1
return value
}()
let firstValue = cached
XCTAssertEqual(firstValue, 1)
XCTAssertEqual(computationCount, 1)
let secondValue = cached
XCTAssertEqual(secondValue, 1)
XCTAssertEqual(computationCount, 1) // Should not recompute
// Change the condition to true to force recomputation
condition = true
let thirdValue = cached
XCTAssertEqual(thirdValue, 2)
XCTAssertEqual(computationCount, 2) // Should recompute
print(computationCount)
- 0.12 Compiled
- 0.08 Passed Solutions
Custom infix operator >>> that composes two functions. The operator should take two functions and return a new function that represents the composition of the two functions (i.e., the output of the first function becomes the input of the second function).
infix operator >>>: FunctionCompositionPrecedence
precedencegroup FunctionCompositionPrecedence { ...
func doubleDescription(_ value: Double) -> String {
return value.description
}
func stringCount(_ value: String) -> Int {
return value.count
}
let composedFunction = doubleDescription >>> stringCount
let result = composedFunction(0.1)
XCTAssertEqual(result, 3)
- 0.63 Compiled
- 0.63 Passed Solutions
Function that computes the SHA-256 hash of data read from a stream with a specified buffer size using Apple's CryptoKit framework.
import CryptoKit
func computeSHA256Hash(of inputStream: InputStream, bufferSize: Int) -> SHA256Digest ...
let data = Data(repeating: 0xAB, count: 1000)
let inputStream = InputStream(data: data)
inputStream.open()
defer {
inputStream.close()
}
let hash = computeSHA256Hash(of: inputStream, bufferSize: 64)
let expectedHash = SHA256.hash(data: data)
XCTAssertEqual(hash, expectedHash)
- 0.25 Compiled
- 0.23 Passed Solutions
Extension to the String type that allows initializing a String from a tuple of 16 Int8 values, where the tuple represents a C-style null-terminated string.
typealias Tuple16 = (Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8)
extension String {
init(tuple16: Tuple16) { ...
let tuple: Tuple16 = (72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33, 0, 0, 0)
let string = String(tuple16: tuple)
XCTAssertEqual(string, "Hello, World!")
let emptyTuple: Tuple16 = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
let emptyString = String(tuple16: emptyTuple)
XCTAssertEqual(emptyString, "")
- 0.15 Compiled
- 0.12 Passed Solutions
Custom operator which provides comparison for two CVPixelBuffer objects and returns true if two pixel buffers equal in size, pixel format, and content.
import CoreVideo
func ==(lhs: CVPixelBuffer, rhs: CVPixelBuffer) -> Bool { ...
func createPixelBuffer(width: Int, height: Int, pixelFormat: OSType) -> CVPixelBuffer? {
var pixelBuffer: CVPixelBuffer?
let status = CVPixelBufferCreate(kCFAllocatorDefault, width, height, pixelFormat, nil, &pixelBuffer)
return status == kCVReturnSuccess ? pixelBuffer : nil
}
func fillPixelBuffer(_ pixelBuffer: CVPixelBuffer, withColor color: UInt8) {
CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly)
defer {
CVPixelBufferUnlockBaseAddress(pixelBuffer, .readOnly)
}
let baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer)
let dataSize = CVPixelBufferGetDataSize(pixelBuffer)
memset(baseAddress, Int32(color), dataSize)
}
let width = 100
let height = 100
let pixelFormat = kCVPixelFormatType_32BGRA
// Identical pixel buffers
let pixelBuffer1 = createPixelBuffer(width: width, height: height, pixelFormat: pixelFormat)!
let pixelBuffer2 = createPixelBuffer(width: width, height: height, pixelFormat: pixelFormat)!
fillPixelBuffer(pixelBuffer1, withColor: 255)
fillPixelBuffer(pixelBuffer2, withColor: 255)
XCTAssertTrue(pixelBuffer1 == pixelBuffer2)
// Pixel buffers with different dimensions
let pixelBuffer3 = createPixelBuffer(width: 100, height: 200, pixelFormat: pixelFormat)!
let pixelBuffer4 = createPixelBuffer(width: 200, height: 100, pixelFormat: pixelFormat)!
fillPixelBuffer(pixelBuffer3, withColor: 255)
fillPixelBuffer(pixelBuffer4, withColor: 255)
XCTAssertFalse(pixelBuffer3 == pixelBuffer4)
// Pixel buffers with different content
let pixelBuffer5 = createPixelBuffer(width: width, height: height, pixelFormat: pixelFormat)!
let pixelBuffer6 = createPixelBuffer(width: width, height: height, pixelFormat: pixelFormat)!
fillPixelBuffer(pixelBuffer5, withColor: 255)
fillPixelBuffer(pixelBuffer6, withColor: 0)
XCTAssertFalse(pixelBuffer5 == pixelBuffer6)
- 0.34 Compiled
- 0.21 Passed Solutions
Function to convert an array of structs with private integer fields into an array of public structs with identical integer fields by directly reinterpreting memory, assuming the structs have the same memory layout and alignment.
struct PrivateItem {
private let value: Int
init(value: Int) {
self.value = value
}
}
struct PublicItem {
let value: Int
}
func reveal(items: [PrivateItem]) -> [PublicItem] { ...
let privateItems = [PrivateItem(value: 0), PrivateItem(value: 1), PrivateItem(value: 2)]
let revealedItems = reveal(items: privateItems)
XCTAssertEqual([0, 1, 2], revealedItems.map(\.value))
- 0.25 Compiled
- 0.22 Passed Solutions
Function that compares two version number strings (created with respect of semantic versioning specification including "alpha" and "beta" tags) and returning their ordering as a value of type ComparisonResult.
enum ComparisonResult {
case orderedSame
case orderedAscending
case orderedDescending
}
func compareVersions(_ lhs: String, _ rhs: String) -> ComparisonResult ...
XCTAssertTrue(compareVersions("1", "1.0.0") == .orderedSame)
XCTAssertTrue(compareVersions("1", "1.0.1") == .orderedAscending)
XCTAssertTrue(compareVersions("1.10", "1.11.0") == .orderedAscending)
XCTAssertTrue(compareVersions("1.10", "0.1") == .orderedDescending)
XCTAssertTrue(compareVersions("1.1-alpha", "1.1-beta") == .orderedAscending)
XCTAssertTrue(compareVersions("1.1-beta", "1.1") == .orderedAscending)
- 0.64 Compiled
- 0.05 Passed Solutions