Skip to content

[Issue-51] Log warnings when fallback image is delivered. #52

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions Sources/YCoreUI/Protocols/ImageAsset.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,30 @@ extension ImageAsset {
/// (prepended to `rawValue`) and `bundle`.
/// - Returns: The named image or else `nil` if the named asset cannot be loaded.
public func loadImage() -> UIImage? {
UIImage(named: calculateName(), in: Self.bundle, compatibleWith: nil)
}

internal func calculateName() -> String {
let name: String
if let validNamespace = Self.namespace {
name = "\(validNamespace)/\(rawValue)"
} else {
name = rawValue
}
return UIImage(named: name, in: Self.bundle, compatibleWith: nil)
return name
}

/// An image asset for this name value.
///
/// Default implementation calls `loadImage` and nil-coalesces to `fallbackImage`.
public var image: UIImage { loadImage() ?? Self.fallbackImage }
public var image: UIImage {
guard let image = loadImage() else {
if YCoreUI.isLoggingEnabled {
YCoreUI.imageLogger.warning("Image named \(calculateName()) failed to load from bundle.")
}
return Self.fallbackImage
}

return image
}
}
11 changes: 10 additions & 1 deletion Sources/YCoreUI/Protocols/SystemImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,14 @@ extension SystemImage {
/// A system image for this name value.
///
/// Default implementation calls `loadImage` and nil-coalesces to `fallbackImage`.
public var image: UIImage { loadImage() ?? Self.fallbackImage }
public var image: UIImage {
guard let image = loadImage() else {
if YCoreUI.isLoggingEnabled {
YCoreUI.imageLogger.warning("System image named \(rawValue) failed to load.")
}
return Self.fallbackImage
}

return image
}
}
21 changes: 21 additions & 0 deletions Sources/YCoreUI/YCoreUI+Logging.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// YCoreUI+Logging.swift
// YCoreUI
//
// Created by Mark Pospesel on 3/16/23.
// Copyright © 2023 Y Media Labs. All rights reserved.
//

import Foundation
import os

/// Y—CoreUI Settings
public struct YCoreUI {
/// Whether console logging for warnings is enabled. Defaults to `true`.
public static var isLoggingEnabled = true
}

internal extension YCoreUI {
/// Logger for warnings related to image loading. cf. `ImageAsset` and `SystemImage`
static let imageLogger = Logger(subsystem: "YCoreUI", category: "images")
}
17 changes: 16 additions & 1 deletion Tests/YCoreUITests/Protocols/ImageAssetTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//

import XCTest
import YCoreUI
@testable import YCoreUI

final class ImageAssetTests: XCTestCase {
func test_bundle() {
Expand Down Expand Up @@ -37,21 +37,36 @@ final class ImageAssetTests: XCTestCase {
func test_loadImageWithoutNameSpace() {
Flags.allCases.forEach {
XCTAssertNotNil($0.loadImage())
XCTAssertNotEqual($0.image.pngData(), DefaultImageAssets.fallbackImage.pngData())
}
}

func test_missingImage() {
YCoreUI.isLoggingEnabled = false

Missing.allCases.forEach {
XCTAssertNil($0.loadImage())
XCTAssertEqual($0.image, UIImage(systemName: "x.squareroot"))
}

YCoreUI.isLoggingEnabled = true
}

func test_imageAsset_defaultValues() {
XCTAssertEqual(DefaultImageAssets.bundle, .main)
XCTAssertEqual(DefaultImageAssets.defaultCase.image.pngData(), DefaultImageAssets.fallbackImage.pngData())
XCTAssertNil(DefaultImageAssets.namespace)
}

func test_calculateName_deliversCorrectName() {
Flags.allCases.forEach {
XCTAssertEqual($0.calculateName(), $0.rawValue)
}

Icons.allCases.forEach {
XCTAssertEqual($0.calculateName(), "Icons/\($0.rawValue)")
}
}
}

enum DefaultImageAssets: String, CaseIterable, ImageAsset {
Expand Down
5 changes: 5 additions & 0 deletions Tests/YCoreUITests/Protocols/SystemImageTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,19 @@ final class SystemImageTests: XCTestCase {
func test_loadImage_deliversImage() {
Symbols.allCases.forEach {
XCTAssertNotNil($0.loadImage())
XCTAssertNotEqual($0.image.pngData(), DefaultSymbols.fallbackImage.pngData())
}
}

func test_missingImage_deliversCustomFallback() {
YCoreUI.isLoggingEnabled = false

MissingSymbols.allCases.forEach {
XCTAssertNil($0.loadImage())
XCTAssertEqual($0.image, UIImage(systemName: "x.squareroot"))
}

YCoreUI.isLoggingEnabled = true
}

func test_systemImage_deliversDefaultFallback() {
Expand Down
16 changes: 16 additions & 0 deletions Tests/YCoreUITests/YCoreUI+LoggingTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// YCoreUI+LoggingTests.swift
// YCoreUI
//
// Created by Mark Pospesel on 3/16/23.
// Copyright © 2023 Y Media Labs. All rights reserved.
//

import XCTest
@testable import YCoreUI

final class YCoreUILoggingTests: XCTestCase {
func testDefaults() {
XCTAssertTrue(YCoreUI.isLoggingEnabled)
}
}