Download apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatImageProcessorTests.swift from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 7.95 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatImageProcessorTests.swift
- Command line
-
hf download hf://SaylorTwift/openclaw/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatImageProcessorTests.swift
-
curl -L -o ChatImageProcessorTests.swift https://huggingface.co/SaylorTwift/openclaw/resolve/main/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatImageProcessorTests.swift
7.95 kB
| import CoreGraphics | |
| import Foundation | |
| import ImageIO | |
| import Testing | |
| import UniformTypeIdentifiers | |
| @testable import OpenClawKit | |
| struct ChatImageProcessorTests { | |
| private func syntheticJPEG(width: Int, height: Int) throws -> Data { | |
| guard | |
| let context = CGContext( | |
| data: nil, | |
| width: width, | |
| height: height, | |
| bitsPerComponent: 8, | |
| bytesPerRow: width * 4, | |
| space: CGColorSpaceCreateDeviceRGB(), | |
| bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) | |
| else { | |
| throw NSError(domain: "ChatImageProcessorTests", code: 1) | |
| } | |
| context.setFillColor(CGColor(red: 0.8, green: 0.2, blue: 0.4, alpha: 1)) | |
| context.fill(CGRect(x: 0, y: 0, width: width, height: height)) | |
| context.setFillColor(CGColor(red: 0.1, green: 0.7, blue: 0.3, alpha: 1)) | |
| context.fill(CGRect(x: 0, y: 0, width: width / 2, height: height / 2)) | |
| guard let image = context.makeImage() else { | |
| throw NSError(domain: "ChatImageProcessorTests", code: 2) | |
| } | |
| let data = NSMutableData() | |
| guard let destination = CGImageDestinationCreateWithData(data, UTType.jpeg.identifier as CFString, 1, nil) | |
| else { | |
| throw NSError(domain: "ChatImageProcessorTests", code: 3) | |
| } | |
| let properties: [CFString: Any] = [ | |
| kCGImageDestinationLossyCompressionQuality: 0.95, | |
| kCGImagePropertyExifDictionary: [ | |
| kCGImagePropertyExifDateTimeOriginal: "2026:04:20 16:30:00", | |
| kCGImagePropertyExifLensModel: "Leaky Lens 50mm f/1.4", | |
| ] as CFDictionary, | |
| kCGImagePropertyGPSDictionary: [ | |
| kCGImagePropertyGPSLatitude: 60.02, | |
| kCGImagePropertyGPSLatitudeRef: "N", | |
| kCGImagePropertyGPSLongitude: 10.95, | |
| kCGImagePropertyGPSLongitudeRef: "E", | |
| ] as CFDictionary, | |
| kCGImagePropertyTIFFDictionary: [ | |
| kCGImagePropertyTIFFMake: "LeakCorp", | |
| kCGImagePropertyTIFFModel: "Privacy-Leaker-1", | |
| ] as CFDictionary, | |
| ] | |
| CGImageDestinationAddImage(destination, image, properties as CFDictionary) | |
| guard CGImageDestinationFinalize(destination) else { | |
| throw NSError(domain: "ChatImageProcessorTests", code: 4) | |
| } | |
| return data as Data | |
| } | |
| private func syntheticPNGWithAlpha(width: Int, height: Int) throws -> Data { | |
| guard | |
| let context = CGContext( | |
| data: nil, | |
| width: width, | |
| height: height, | |
| bitsPerComponent: 8, | |
| bytesPerRow: width * 4, | |
| space: CGColorSpaceCreateDeviceRGB(), | |
| bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) | |
| else { | |
| throw NSError(domain: "ChatImageProcessorTests", code: 5) | |
| } | |
| context.clear(CGRect(x: 0, y: 0, width: width, height: height)) | |
| context.setFillColor(CGColor(red: 1, green: 0, blue: 0, alpha: 1)) | |
| context.fill(CGRect(x: width / 4, y: height / 4, width: width / 2, height: height / 2)) | |
| guard let image = context.makeImage() else { | |
| throw NSError(domain: "ChatImageProcessorTests", code: 6) | |
| } | |
| let data = NSMutableData() | |
| guard let destination = CGImageDestinationCreateWithData(data, UTType.png.identifier as CFString, 1, nil) | |
| else { | |
| throw NSError(domain: "ChatImageProcessorTests", code: 7) | |
| } | |
| CGImageDestinationAddImage(destination, image, nil) | |
| guard CGImageDestinationFinalize(destination) else { | |
| throw NSError(domain: "ChatImageProcessorTests", code: 8) | |
| } | |
| return data as Data | |
| } | |
| private func properties(for data: Data) -> [CFString: Any] { | |
| guard | |
| let source = CGImageSourceCreateWithData(data as CFData, nil), | |
| let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [CFString: Any] | |
| else { | |
| return [:] | |
| } | |
| return properties | |
| } | |
| private func dimensions(for data: Data) -> (width: Int, height: Int)? { | |
| let properties = self.properties(for: data) | |
| guard | |
| let width = properties[kCGImagePropertyPixelWidth] as? NSNumber, | |
| let height = properties[kCGImagePropertyPixelHeight] as? NSNumber | |
| else { | |
| return nil | |
| } | |
| return (width.intValue, height.intValue) | |
| } | |
| func `resizes landscape long edge to upload limit`() throws { | |
| let source = try self.syntheticJPEG(width: 4000, height: 3000) | |
| let output = try ChatImageProcessor.processForUpload(data: source) | |
| let dimensions = try #require(self.dimensions(for: output)) | |
| #expect(max(dimensions.width, dimensions.height) <= ChatImageProcessor.maxLongEdgePx) | |
| #expect(abs((Double(dimensions.width) / Double(dimensions.height)) - (4000.0 / 3000.0)) <= 0.02) | |
| } | |
| func `resizes portrait long edge to upload limit`() throws { | |
| let source = try self.syntheticJPEG(width: 3000, height: 4000) | |
| let output = try ChatImageProcessor.processForUpload(data: source) | |
| let dimensions = try #require(self.dimensions(for: output)) | |
| #expect(max(dimensions.width, dimensions.height) <= ChatImageProcessor.maxLongEdgePx) | |
| #expect(abs((Double(dimensions.width) / Double(dimensions.height)) - (3000.0 / 4000.0)) <= 0.02) | |
| } | |
| func `resizes narrow tall long edge to upload limit`() throws { | |
| let source = try self.syntheticJPEG(width: 1080, height: 2400) | |
| let output = try ChatImageProcessor.processForUpload(data: source) | |
| let dimensions = try #require(self.dimensions(for: output)) | |
| #expect(max(dimensions.width, dimensions.height) <= ChatImageProcessor.maxLongEdgePx) | |
| #expect(abs((Double(dimensions.width) / Double(dimensions.height)) - (1080.0 / 2400.0)) <= 0.02) | |
| } | |
| func `small image is not upscaled`() throws { | |
| let source = try self.syntheticJPEG(width: 400, height: 300) | |
| let output = try ChatImageProcessor.processForUpload(data: source) | |
| let dimensions = try #require(self.dimensions(for: output)) | |
| #expect(max(dimensions.width, dimensions.height) <= 400) | |
| } | |
| func `output fits payload budget`() throws { | |
| let source = try self.syntheticJPEG(width: 4000, height: 3000) | |
| let output = try ChatImageProcessor.processForUpload(data: source) | |
| #expect(output.count <= ChatImageProcessor.maxPayloadBytes) | |
| } | |
| func `rejects non image data`() { | |
| let garbage = Data("not an image".utf8) | |
| #expect(throws: ChatImageProcessor.ProcessError.self) { | |
| _ = try ChatImageProcessor.processForUpload(data: garbage) | |
| } | |
| } | |
| func `strips source metadata from output`() throws { | |
| let source = try self.syntheticJPEG(width: 3000, height: 2000) | |
| let output = try ChatImageProcessor.processForUpload(data: source) | |
| let properties = self.properties(for: output) | |
| let gps = properties[kCGImagePropertyGPSDictionary] as? [CFString: Any] ?? [:] | |
| #expect(gps.isEmpty) | |
| for needle in ["Leaky Lens", "LeakCorp", "Privacy-Leaker", "2026:04:20"] { | |
| #expect(output.range(of: Data(needle.utf8)) == nil) | |
| } | |
| } | |
| func `flattens transparent sources to opaque JPEG`() throws { | |
| let source = try self.syntheticPNGWithAlpha(width: 800, height: 600) | |
| let output = try ChatImageProcessor.processForUpload(data: source) | |
| let imageSource = try #require(CGImageSourceCreateWithData(output as CFData, nil)) | |
| let image = try #require(CGImageSourceCreateImageAtIndex(imageSource, 0, nil)) | |
| #expect([.none, .noneSkipFirst, .noneSkipLast].contains(image.alphaInfo)) | |
| } | |
| } | |