From 016b4a5248dec8ea00cd50245742f2aff14a9b3b Mon Sep 17 00:00:00 2001 From: Benedek Kozma Date: Thu, 27 Feb 2025 16:52:53 +0100 Subject: [PATCH 1/7] Add CacheControl tests --- .../HummingbirdTests/CacheControlTests.swift | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Tests/HummingbirdTests/CacheControlTests.swift diff --git a/Tests/HummingbirdTests/CacheControlTests.swift b/Tests/HummingbirdTests/CacheControlTests.swift new file mode 100644 index 00000000..ac0fb3a8 --- /dev/null +++ b/Tests/HummingbirdTests/CacheControlTests.swift @@ -0,0 +1,26 @@ +import Hummingbird +import XCTest + +final class CacheControlTests: XCTestCase { + func testCssIsText() { + let cacheControl = CacheControl([ + (MediaType(type: .text), [.noCache, .public]), + ]) + XCTAssertEqual(cacheControl.getCacheControlHeader(for: "test.css"), "no-cache, public") + } + + func testMultipleEntries() { + let cacheControl = CacheControl([ + (MediaType.textCss, [.noStore]), + (MediaType.text, [.noCache, .public]), + ]) + XCTAssertEqual(cacheControl.getCacheControlHeader(for: "test.css"), "no-store") + } + + func testCssIsAny() { + let cacheControl = CacheControl([ + (MediaType(type: .any), [.noCache, .public]), + ]) + XCTAssertEqual(cacheControl.getCacheControlHeader(for: "test.css"), "no-cache, public") + } +} From 95598edb6dc4c816a1cbbe7b580322af3ef8892a Mon Sep 17 00:00:00 2001 From: Benedek Kozma Date: Thu, 27 Feb 2025 16:54:25 +0100 Subject: [PATCH 2/7] format files --- Tests/HummingbirdTests/CacheControlTests.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Tests/HummingbirdTests/CacheControlTests.swift b/Tests/HummingbirdTests/CacheControlTests.swift index ac0fb3a8..a1a683d2 100644 --- a/Tests/HummingbirdTests/CacheControlTests.swift +++ b/Tests/HummingbirdTests/CacheControlTests.swift @@ -4,23 +4,23 @@ import XCTest final class CacheControlTests: XCTestCase { func testCssIsText() { let cacheControl = CacheControl([ - (MediaType(type: .text), [.noCache, .public]), - ]) + (MediaType(type: .text), [.noCache, .public]) + ]) XCTAssertEqual(cacheControl.getCacheControlHeader(for: "test.css"), "no-cache, public") } func testMultipleEntries() { let cacheControl = CacheControl([ - (MediaType.textCss, [.noStore]), - (MediaType.text, [.noCache, .public]), - ]) + (MediaType.textCss, [.noStore]), + (MediaType.text, [.noCache, .public]), + ]) XCTAssertEqual(cacheControl.getCacheControlHeader(for: "test.css"), "no-store") } func testCssIsAny() { let cacheControl = CacheControl([ - (MediaType(type: .any), [.noCache, .public]), - ]) + (MediaType(type: .any), [.noCache, .public]) + ]) XCTAssertEqual(cacheControl.getCacheControlHeader(for: "test.css"), "no-cache, public") } } From 1aa02f3c21a9351ed5b85ee55eed7f5be008cfa3 Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Thu, 27 Feb 2025 16:20:48 +0000 Subject: [PATCH 3/7] Fix cache control test for MediaType.any --- Sources/Hummingbird/HTTP/MediaType.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Hummingbird/HTTP/MediaType.swift b/Sources/Hummingbird/HTTP/MediaType.swift index aeaf587a..8840f489 100644 --- a/Sources/Hummingbird/HTTP/MediaType.swift +++ b/Sources/Hummingbird/HTTP/MediaType.swift @@ -126,8 +126,8 @@ public struct MediaType: Sendable, CustomStringConvertible { /// Return if media type matches the input public func isType(_ type: MediaType) -> Bool { - guard self.type == type.type, - self.subType == type.subType || type.subType == "*" + guard + (self.type == type.type && (self.subType == type.subType || type.subType == "*")) || type.type == .any else { return false } From 63e1f384a1cd108b4915502f85722fd9e855c128 Mon Sep 17 00:00:00 2001 From: Benedek Kozma Date: Thu, 27 Feb 2025 19:16:06 +0100 Subject: [PATCH 4/7] Remove non-transitive equality implementation --- Sources/Hummingbird/HTTP/MediaType.swift | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/Sources/Hummingbird/HTTP/MediaType.swift b/Sources/Hummingbird/HTTP/MediaType.swift index 8840f489..0ce28533 100644 --- a/Sources/Hummingbird/HTTP/MediaType.swift +++ b/Sources/Hummingbird/HTTP/MediaType.swift @@ -154,7 +154,7 @@ public struct MediaType: Sendable, CustomStringConvertible { /// Media type categories public struct Category: Sendable, Equatable, RawRepresentable, CustomStringConvertible { - internal enum Internal: String, Sendable, Equatable { + internal enum Internal: String, Sendable { case application case audio case example @@ -166,15 +166,6 @@ public struct MediaType: Sendable, CustomStringConvertible { case text case video case any - - public static func == (_ lhs: Self, _ rhs: Self) -> Bool { - switch (lhs, rhs) { - case (.any, _), (_, .any): - return true - default: - return lhs.rawValue == rhs.rawValue - } - } } let value: Internal From 2ce93f03556ce94ecf944c5129c90aeb97861d67 Mon Sep 17 00:00:00 2001 From: Benedek Kozma Date: Thu, 27 Feb 2025 21:31:58 +0100 Subject: [PATCH 5/7] Remove Category.Internal, implement pattern matching operator --- Sources/Hummingbird/HTTP/MediaType.swift | 68 +++++++++--------------- 1 file changed, 24 insertions(+), 44 deletions(-) diff --git a/Sources/Hummingbird/HTTP/MediaType.swift b/Sources/Hummingbird/HTTP/MediaType.swift index 0ce28533..c8e62073 100644 --- a/Sources/Hummingbird/HTTP/MediaType.swift +++ b/Sources/Hummingbird/HTTP/MediaType.swift @@ -126,8 +126,8 @@ public struct MediaType: Sendable, CustomStringConvertible { /// Return if media type matches the input public func isType(_ type: MediaType) -> Bool { - guard - (self.type == type.type && (self.subType == type.subType || type.subType == "*")) || type.type == .any + guard self.type ~= type.type, + self.subType == type.subType || type.subType == "*" else { return false } @@ -153,50 +153,30 @@ public struct MediaType: Sendable, CustomStringConvertible { } /// Media type categories - public struct Category: Sendable, Equatable, RawRepresentable, CustomStringConvertible { - internal enum Internal: String, Sendable { - case application - case audio - case example - case font - case image - case message - case model - case multipart - case text - case video - case any - } - - let value: Internal - init(value: Internal) { - self.value = value - } - - public init?(rawValue: String) { - guard let value = Internal(rawValue: rawValue) else { return nil } - self.value = value - } - - public var rawValue: String { - self.value.rawValue - } - - public var description: String { - self.value.rawValue + public enum Category: String, Sendable, Equatable, RawRepresentable, CustomStringConvertible { + case application + case audio + case example + case font + case image + case message + case model + case multipart + case text + case video + case any + + static func ~= (_ lhs: Self, _ rhs: Self) -> Bool { + switch (lhs, rhs) { + case (.any, _), + (_, .any): + true + default: + lhs == rhs + } } - public static var application: Self { .init(value: .application) } - public static var audio: Self { .init(value: .audio) } - public static var example: Self { .init(value: .example) } - public static var font: Self { .init(value: .font) } - public static var image: Self { .init(value: .image) } - public static var message: Self { .init(value: .message) } - public static var model: Self { .init(value: .model) } - public static var multipart: Self { .init(value: .multipart) } - public static var text: Self { .init(value: .text) } - public static var video: Self { .init(value: .video) } - public static var any: Self { .init(value: .any) } + public var description: String { rawValue } } static let tSpecial = Set(["(", ")", "<", ">", "@", ",", ";", ":", "\\", "\"", "/", "[", "]", "?", ".", "="]) From d37dfffa5acd1807bde08b51c5fe771685a3d756 Mon Sep 17 00:00:00 2001 From: Benedek Kozma Date: Thu, 27 Feb 2025 21:33:41 +0100 Subject: [PATCH 6/7] both cases in single line --- Sources/Hummingbird/HTTP/MediaType.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/Hummingbird/HTTP/MediaType.swift b/Sources/Hummingbird/HTTP/MediaType.swift index c8e62073..e02b5985 100644 --- a/Sources/Hummingbird/HTTP/MediaType.swift +++ b/Sources/Hummingbird/HTTP/MediaType.swift @@ -168,8 +168,7 @@ public struct MediaType: Sendable, CustomStringConvertible { static func ~= (_ lhs: Self, _ rhs: Self) -> Bool { switch (lhs, rhs) { - case (.any, _), - (_, .any): + case (.any, _), (_, .any): true default: lhs == rhs From 964aad520013404c4c92e72743f1beaa14b33ea8 Mon Sep 17 00:00:00 2001 From: Benedek Kozma Date: Fri, 28 Feb 2025 17:28:04 +0100 Subject: [PATCH 7/7] restore internal enum --- Sources/Hummingbird/HTTP/MediaType.swift | 60 ++++++++++++++++++------ 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/Sources/Hummingbird/HTTP/MediaType.swift b/Sources/Hummingbird/HTTP/MediaType.swift index e02b5985..01c56510 100644 --- a/Sources/Hummingbird/HTTP/MediaType.swift +++ b/Sources/Hummingbird/HTTP/MediaType.swift @@ -153,29 +153,59 @@ public struct MediaType: Sendable, CustomStringConvertible { } /// Media type categories - public enum Category: String, Sendable, Equatable, RawRepresentable, CustomStringConvertible { - case application - case audio - case example - case font - case image - case message - case model - case multipart - case text - case video - case any + public struct Category: Sendable, Equatable, RawRepresentable, CustomStringConvertible { + internal enum Internal: String, Sendable { + case application + case audio + case example + case font + case image + case message + case model + case multipart + case text + case video + case any + } + + let value: Internal + init(value: Internal) { + self.value = value + } + + public init?(rawValue: String) { + guard let value = Internal(rawValue: rawValue) else { return nil } + self.value = value + } + + public var rawValue: String { + self.value.rawValue + } + + public var description: String { + self.value.rawValue + } static func ~= (_ lhs: Self, _ rhs: Self) -> Bool { - switch (lhs, rhs) { + switch (lhs.value, rhs.value) { case (.any, _), (_, .any): true default: - lhs == rhs + lhs.value == rhs.value } } - public var description: String { rawValue } + public static var application: Self { .init(value: .application) } + public static var audio: Self { .init(value: .audio) } + public static var example: Self { .init(value: .example) } + public static var font: Self { .init(value: .font) } + public static var image: Self { .init(value: .image) } + public static var message: Self { .init(value: .message) } + public static var model: Self { .init(value: .model) } + public static var multipart: Self { .init(value: .multipart) } + public static var text: Self { .init(value: .text) } + public static var video: Self { .init(value: .video) } + public static var any: Self { .init(value: .any) } } static let tSpecial = Set(["(", ")", "<", ">", "@", ",", ";", ":", "\\", "\"", "/", "[", "]", "?", ".", "="])