Skip to content

Commit

Permalink
Merge pull request #28 from RougeWare/feature/27-Codable
Browse files Browse the repository at this point in the history
#27: Added Codable support
  • Loading branch information
KyLeggiero committed Oct 18, 2021
2 parents e8faad3 + 4a58006 commit 2c0d302
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 24 deletions.
47 changes: 47 additions & 0 deletions Sources/SemVer/Semantic Version + Codable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// Semantic Version + Codable.swift
// SemVer
//
// Created by Ky Leggiero on 2021-10-18.
//

import Foundation



extension SemVer: Encodable {

/// Encodes this semantic version to the given container
/// - Throws any error which occurs when encoding
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(description)
}
}



extension SemVer: Decodable {

/// Decodes a semantic version from its encoded form
/// - Throws any error which occurs when decoding, including a `SemVer.DecodingError` if that's specialized to Semantic Version decoding
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let raw = try container.decode(String.self)

guard let parsed = Self.init(raw) else {
throw DecodingError.invalidSemanticVersion(encodedForm: raw)
}

self = parsed
}



/// An error that migth occur when decoding a semantic version
enum DecodingError: Error {

/// The encoded form of the semantic version was an invalid semantic version
case invalidSemanticVersion(encodedForm: String)
}
}
33 changes: 27 additions & 6 deletions Sources/SemVer/Testing tools.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,32 @@ import Foundation



/// A bodge to change behavior based on whether a test suite is running.
///
/// Ideally, this would be a compile-time flag. However, it seems that isn't being respected with my current setup, so I don't trust it.
internal var isTesting = false
/// Some tools to help us better-test this module
internal enum TestingTools {
// Empty on-purpose; all members are in static extensions
}



internal extension TestingTools {

/// A bodge to change behavior based on whether a test suite is running.
///
/// Ideally, this would be a compile-time flag. However, it seems that isn't being respected with my current setup, so I don't trust it.
static var isTesting = false


/// In non-test runs, this indicates that an internal sanity check failed.
///
/// To perform an assertion in test runs as well, use `Swift.assertionFailure` instead.
///
/// - Parameter message: _optional_ - A string to print in a playground or `-Onone` non-test build. Defaults to an empty string.
@inline(__always)
static func assertionFailure(_ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) {
guard !isTesting else { return }
Swift.assertionFailure(message(), file: file, line: line)
}
}



Expand All @@ -24,6 +46,5 @@ internal var isTesting = false
/// - Parameter message: _optional_ - A string to print in a playground or `-Onone` non-test build. Defaults to an empty string.
@inline(__always)
internal func assertionFailure(_ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) {
guard !isTesting else { return }
Swift.assertionFailure(message(), file: file, line: line)
TestingTools.assertionFailure(message(), file: file, line: line)
}
8 changes: 2 additions & 6 deletions Tests/SemVerTests/SemVer mutations tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,11 @@
//

import XCTest
@testable import SemVer
import SemVer



class SemVerMutationTests: XCTestCase {

override func setUp() {
isTesting = true
}
class SemVerMutationTests: SemVerTestClass {


// MARK: - Increment
Expand Down
104 changes: 104 additions & 0 deletions Tests/SemVerTests/SemVer+Codable Tests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//
// SemVer+Codable Tests.swift
//
//
// Created by Ky Leggiero on 2021-10-18.
//

import XCTest
import SemVer



class SemVerCodableTests: SemVerTestClass {

func testEncode() throws {
let encoder = JSONEncoder()


func encode(_ semVer: SemVer) throws -> String {
String(data: try encoder.encode(Test(semVer)), encoding: .utf8)!
}


func expect(_ output: String) -> String {
#"{"semVer":"\#(output)"}"#
}


XCTAssertEqual(expect("0.0.0"), try encode(SemVer(0,0,0)))
XCTAssertEqual(expect("0.0.1"), try encode(SemVer(0,0,1)))
XCTAssertEqual(expect("0.1.0"), try encode(SemVer(0,1,0)))
XCTAssertEqual(expect("1.0.0"), try encode(SemVer(1,0,0)))
XCTAssertEqual(expect("0.0.999"), try encode(SemVer(0,0,999)))
XCTAssertEqual(expect("0.999.0"), try encode(SemVer(0,999,0)))
XCTAssertEqual(expect("999.0.0"), try encode(SemVer(999,0,0)))

XCTAssertEqual(expect("1.2.3-RC.4+567"), try encode(SemVer(01,2,3, preRelease: "RC.4", build: 567)!))
XCTAssertEqual(expect("1.2.3-RC.4+567"), try encode(SemVer(01,2,3, preRelease: ["RC","4"], build: 567)!))
XCTAssertEqual(expect("1.2.3-RC.4+567"), try encode(SemVer(01,2,3, preRelease: ["RC","4"], build: [567])!))
XCTAssertEqual(expect("1.2.3-RC.4+567"), try encode(SemVer("1.2.3-RC.4+567")!))
}


func testDecode() throws {
let decoder = JSONDecoder()


func decode(_ semVer: String) throws -> SemVer {
try decoder.decode(Test.self, from: #"{"semVer":"\#(semVer)"}"#.data(using: .utf8)!).semVer
}


XCTAssertEqual(SemVer(0,0,0), try decode("0.0.0"))
XCTAssertEqual(SemVer(0,0,1), try decode("0.0.1"))
XCTAssertEqual(SemVer(0,1,0), try decode("0.1.0"))
XCTAssertEqual(SemVer(1,0,0), try decode("1.0.0"))
XCTAssertEqual(SemVer(0,0,999), try decode("0.0.999"))
XCTAssertEqual(SemVer(0,999,0), try decode("0.999.0"))
XCTAssertEqual(SemVer(999,0,0), try decode("999.0.0"))

XCTAssertEqual(SemVer(01,2,3, preRelease: "RC.4", build: 567)!, try decode("1.2.3-RC.4+567"))
XCTAssertEqual(SemVer(01,2,3, preRelease: ["RC","4"], build: 567)!, try decode("1.2.3-RC.4+567"))
XCTAssertEqual(SemVer(01,2,3, preRelease: ["RC","4"], build: [567])!, try decode("1.2.3-RC.4+567"))
XCTAssertEqual(SemVer("1.2.3-RC.4+567")!, try decode("1.2.3-RC.4+567"))
}


func testEncodeDecode() {
let encoder = JSONEncoder()
let decoder = JSONDecoder()


func encodeDecode(_ semVer: SemVer) throws -> SemVer {
try decoder.decode(Test.self, from: try encoder.encode(Test(semVer))).semVer
}



XCTAssertEqual(SemVer(0,0,0), try encodeDecode(SemVer(0,0,0)))
XCTAssertEqual(SemVer(0,0,1), try encodeDecode(SemVer(0,0,1)))
XCTAssertEqual(SemVer(0,1,0), try encodeDecode(SemVer(0,1,0)))
XCTAssertEqual(SemVer(1,0,0), try encodeDecode(SemVer(1,0,0)))
XCTAssertEqual(SemVer(0,0,999), try encodeDecode(SemVer(0,0,999)))
XCTAssertEqual(SemVer(0,999,0), try encodeDecode(SemVer(0,999,0)))
XCTAssertEqual(SemVer(999,0,0), try encodeDecode(SemVer(999,0,0)))

XCTAssertEqual(SemVer(01,2,3, preRelease: "RC.4", build: 567)!, try encodeDecode(SemVer(01,2,3, preRelease: "RC.4", build: 567)!))
XCTAssertEqual(SemVer(01,2,3, preRelease: ["RC","4"], build: 567)!, try encodeDecode(SemVer(01,2,3, preRelease: ["RC","4"], build: 567)!))
XCTAssertEqual(SemVer(01,2,3, preRelease: ["RC","4"], build: [567])!, try encodeDecode(SemVer(01,2,3, preRelease: ["RC","4"], build: [567])!))
XCTAssertEqual(SemVer("1.2.3-RC.4+567")!, try encodeDecode(SemVer("1.2.3-RC.4+567")!))
}
}



private struct Test: Codable {

let semVer: SemVer


init(_ semVer: SemVer) {
self.semVer = semVer
}
}
8 changes: 2 additions & 6 deletions Tests/SemVerTests/SemVer+Hashable Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,11 @@
//

import XCTest
@testable import SemVer
import SemVer



class SemVerHashableTests: XCTestCase {

override func setUp() {
isTesting = true
}
class SemVerHashableTests: SemVerTestClass {


func testHashable() {
Expand Down
8 changes: 2 additions & 6 deletions Tests/SemVerTests/SemVerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,11 @@
//

import XCTest
@testable import SemVer
import SemVer



class SemVerTests: XCTestCase {

override func setUp() {
isTesting = true
}
class SemVerTests: SemVerTestClass {


func testDescription() {
Expand Down
40 changes: 40 additions & 0 deletions Tests/SemVerTests/Testing tools.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// Testing tools.swift
// SemVerTests
//
// Created by Ky Leggiero on 2021-10-18.
//

import XCTest
@testable import SemVer



internal class SemVerTestClass: XCTestCase {
override func setUp() {
isTesting = true
super.setUp()
}
}



/// A bodge to change behavior based on whether a test suite is running.
///
/// Ideally, this would be a compile-time flag. However, it seems that isn't being respected with my current setup, so I don't trust it.
@inline(__always)
var isTesting: Bool {
get { TestingTools.isTesting }
set { TestingTools.isTesting = newValue }
}


/// In non-test runs, this indicates that an internal sanity check failed.
///
/// To perform an assertion in test runs as well, use `Swift.assertionFailure` instead.
///
/// - Parameter message: _optional_ - A string to print in a playground or `-Onone` non-test build. Defaults to an empty string.
@inline(__always)
func assertionFailure(_ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) {
TestingTools.assertionFailure(message(), file: file, line: line)
}

0 comments on commit 2c0d302

Please sign in to comment.