Skip to content

Commit

Permalink
Merge pull request #10 from jordanbaird/stop-collecting-code-coverage
Browse files Browse the repository at this point in the history
Stop collecting code coverage

This kind of framework is hard to test. More often than not, small changes result in big coverage losses, and some of the tests only exist to satisfy Codecov and don't really "test" anything.
  • Loading branch information
jordanbaird committed Oct 30, 2022
2 parents 6ed1ade + 48c20aa commit da719c0
Show file tree
Hide file tree
Showing 17 changed files with 500 additions and 325 deletions.
11 changes: 1 addition & 10 deletions .github/workflows/main.yml
Expand Up @@ -11,14 +11,5 @@ jobs:
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: Build
run: swift build
- name: Test
run: swift test --enable-code-coverage
- name: Generate
run: ./.github/scripts/generate-code-coverage.sh
- name: Upload Code Coverage
uses: codecov/codecov-action@v3.1.0
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./info.lcov
run: swift test
2 changes: 0 additions & 2 deletions README.md
Expand Up @@ -8,7 +8,6 @@
</h1>

[![Continuous Integration][ci-badge]](https://github.com/jordanbaird/SwiftKeys/actions/workflows/main.yml)
[![Code Coverage][codecov-badge]](https://codecov.io/gh/jordanbaird/SwiftKeys)
[![Release][release-badge]](https://github.com/jordanbaird/SwiftKeys/releases/latest)
[![Swift Versions][versions-badge]](https://swiftpackageindex.com/jordanbaird/SwiftKeys)
[![Docs][docs-badge]](https://swiftpackageindex.com/jordanbaird/SwiftKeys/documentation)
Expand Down Expand Up @@ -124,7 +123,6 @@ SwiftKeys is available under the MIT license. See the LICENSE file for more info
[recorder-window~dark]: Sources/SwiftKeys/Documentation.docc/Resources/recorder-window~dark.png

[ci-badge]: https://img.shields.io/github/workflow/status/jordanbaird/SwiftKeys/Continuous%20Integration?style=flat-square
[codecov-badge]: https://img.shields.io/codecov/c/github/jordanbaird/SwiftKeys?label=codecov&logo=codecov&style=flat-square
[release-badge]: https://img.shields.io/github/v/release/jordanbaird/SwiftKeys?style=flat-square
[versions-badge]: https://img.shields.io/badge/dynamic/json?color=F05138&label=Swift&query=%24.message&url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fjordanbaird%2FSwiftKeys%2Fbadge%3Ftype%3Dswift-versions&style=flat-square
[docs-badge]: https://img.shields.io/static/v1?label=%20&message=documentation&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAEsSURBVHgB7dntDYIwEAbgV+MAuoEj6AaO4AiO4AayAbqBbuAGjoIbwAbnHT8MMTH9uEJrvCch/FB7vEh7EABjjBMRnXhrKY1GxsNUuFhN45gmBKU783lCDKtBiYeoUoeYI79KE6KEACI6RCkBRFSIkgKI4BClBRBBIUoMILxDlBpASIgjtBL3gR2FaV1jzjyKvg98xqDEw615t3Z87eFbc/IAPkJqljwHvFiA3CxAbhaAdI+cNZTUfWD4edQBOMacog9cEE/z25514twsQG4/H2ABJZ5vG97tEefKc/QJhRR9oIH7AeWbjodchdYcSnEJLRGvg5L6EmJb3g6Ic4eSNbLcLEBuf9HIZKnrl0rtvX8E5zLr8w+o79kVbkiBT/yZxn3Z90lqVTDGOL0AoGWIIaQgyakAAAAASUVORK5CYII=&color=F05138&labelColor=gray&style=flat-square
Expand Down
25 changes: 19 additions & 6 deletions Sources/SwiftKeys/Documentation.docc/Extensions/KeyCommand.md
Expand Up @@ -77,18 +77,22 @@ print(originalCommand.modifiers)

### Creating

- ``init(name:key:modifiers:)-5m38h``
- ``init(name:key:modifiers:)-7ly66``
- ``init(name:key:modifiers:)-41zy0``
- ``init(name:)``

### Observing

- ``Observation``
- ``EventType``
- ``name-swift.property``
- ``key-swift.property``
- ``modifiers``
- ``observe(_:handler:)``
- ``removeObservation(_:)``
- ``removeObservations(_:)``
- ``removeObservations(where:)``
- ``removeFirstObservation(where:)``
- ``removeAllObservations()``
- ``addObservation(_:)``

### Changing State

Expand All @@ -97,8 +101,17 @@ print(originalCommand.modifiers)
- ``remove()``
- ``isEnabled``

### Naming and Prefixing
### Running a Key Command's Handlers

- ``name-swift.property``
Sometimes, it's useful to be able to run the handlers stored under a key command without having to wait for it to trigger. You can do so using the following methods:

- ``runHandlers(for:)``
- ``runHandlers(where:)``

### Nested Types

- ``Observation``
- ``Name-swift.struct``
- ``Name-swift.struct/Prefix-swift.class``
- ``Key-swift.enum``
- ``Modifier``
- ``EventType``
24 changes: 13 additions & 11 deletions Sources/SwiftKeys/KeyCommand/KeyCommand.swift
Expand Up @@ -32,14 +32,13 @@ public struct KeyCommand {
/// The name that is used to store the key command.
public let name: Name

/// The underlying object associated with the key command.
/// The underlying proxy object associated with the key command,
/// stored and retrieved using the key command's name.
///
/// - Note: If no proxy object has been stored at the time of
/// access, a new object will be created and stored.
var proxy: Proxy {
if let proxy = ProxyStorage.proxy(with: name) {
return proxy
}
let proxy = Proxy(name: name)
ProxyStorage.store(proxy)
return proxy
ProxyStorage.proxy(with: name) ?? Proxy(with: name, storing: true)
}

/// A Boolean value that indicates whether the key command is currently
Expand Down Expand Up @@ -92,7 +91,7 @@ public struct KeyCommand {
///
/// - Note: The underlying object's key and modifiers will be updated to
/// match the ones provided in this initializer. If this behavior is undesired,
/// use ``init(name:)`` instead.
/// use ``KeyCommand/init(name:)`` instead.
public init(name: Name, key: Key, modifiers: [Modifier]) {
self.init(name: name)
proxy.mutateWithoutChangingRegistrationState {
Expand All @@ -109,7 +108,7 @@ public struct KeyCommand {
///
/// - Note: The underlying object's key and modifiers will be updated to
/// match the ones provided in this initializer. If this behavior is undesired,
/// use ``init(name:)`` instead.
/// use ``KeyCommand/init(name:)`` instead.
public init(name: Name, key: Key, modifiers: Modifier...) {
self.init(name: name, key: key, modifiers: modifiers)
}
Expand Down Expand Up @@ -153,6 +152,9 @@ public struct KeyCommand {
///
/// When the command is triggered, the observations attached to it will
/// be executed synchronously in the order they were added.
///
/// You typically shouldn't need to use this method;
/// prefer ``observe(_:handler:)``.
public func addObservation(_ observation: Observation) {
if !proxy.keyCommandObservations.contains(observation) {
proxy.keyCommandObservations.append(observation)
Expand Down Expand Up @@ -375,9 +377,9 @@ extension KeyCommand {

init?(_ eventKind: Int) {
switch eventKind {
case kEventHotKeyPressed:
case kEventHotKeyPressed, kEventRawKeyDown:
self = .keyDown
case kEventHotKeyReleased:
case kEventHotKeyReleased, kEventRawKeyUp:
self = .keyUp
default:
return nil
Expand Down
15 changes: 9 additions & 6 deletions Sources/SwiftKeys/KeyCommand/Proxy.swift
Expand Up @@ -82,9 +82,12 @@ final class Proxy {
.init(self)
}

init(name: KeyCommand.Name) {
init(with name: KeyCommand.Name, storing shouldStore: Bool = false) {
self.name = name
Self.proxyCount += 1
if shouldStore {
ProxyStorage.store(self)
}
}

static func install() -> OSStatus {
Expand Down Expand Up @@ -214,6 +217,11 @@ final class Proxy {
0,
&hotKeyRef)

guard status == noErr else {
KeyCommandError.registrationFailed(code: status).log()
return
}

// We need to retain a reference to each proxy instance. The C
// function inside of the `install()` method can't deal with
// context, so we can't inject or reference `self`. We _do_ have
Expand All @@ -222,11 +230,6 @@ final class Proxy {
// C function.
ProxyStorage.store(self)

guard status == noErr else {
KeyCommandError.registrationFailed(code: status).log()
return
}

do {
let data = try JSONEncoder().encode(KeyCommand(name: name))
UserDefaults.standard.set(data, forKey: name.combinedValue)
Expand Down
105 changes: 78 additions & 27 deletions Sources/SwiftKeys/KeyRecorder/KeyRecorder.swift
Expand Up @@ -205,8 +205,12 @@ public final class KeyRecorder: NSControl {
segmentedControl = .init(command: command)
super.init(frame: segmentedControl.frame)
translatesAutoresizingMaskIntoConstraints = false
widthAnchor.constraint(equalToConstant: segmentedControl.frame.width).isActive = true
heightAnchor.constraint(equalToConstant: segmentedControl.frame.height).isActive = true
widthAnchor.constraint(
equalToConstant: segmentedControl.frame.width
).isActive = true
heightAnchor.constraint(
equalToConstant: segmentedControl.frame.height
).isActive = true
addSubview(segmentedControl)
}

Expand Down Expand Up @@ -237,8 +241,12 @@ public final class KeyRecorder: NSControl {
private func addBackingView() {
addSubview(backingView, positioned: .below, relativeTo: self)
backingView.translatesAutoresizingMaskIntoConstraints = false
backingView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
backingView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
backingView.centerXAnchor.constraint(
equalTo: centerXAnchor
).isActive = true
backingView.centerYAnchor.constraint(
equalTo: centerYAnchor
).isActive = true
backingView.widthAnchor.constraint(
equalTo: widthAnchor,
constant: bezelStyle.widthConstant
Expand All @@ -256,8 +264,12 @@ public final class KeyRecorder: NSControl {
private func addBorderView() {
addSubview(borderView, positioned: .below, relativeTo: segmentedControl)
borderView.translatesAutoresizingMaskIntoConstraints = false
borderView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
borderView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
borderView.centerXAnchor.constraint(
equalTo: centerXAnchor
).isActive = true
borderView.centerYAnchor.constraint(
equalTo: centerYAnchor
).isActive = true
borderView.widthAnchor.constraint(
equalTo: widthAnchor,
constant: bezelStyle.widthConstant
Expand All @@ -282,10 +294,20 @@ public final class KeyRecorder: NSControl {
highlightView.material = highlightStyle.material
highlightView.layer?.backgroundColor = highlightStyle.highlightColor.cgColor
highlightView.translatesAutoresizingMaskIntoConstraints = false
highlightView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
highlightView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
highlightView.widthAnchor.constraint(equalTo: widthAnchor, constant: -4).isActive = true
highlightView.heightAnchor.constraint(equalTo: heightAnchor, constant: -2).isActive = true
highlightView.centerXAnchor.constraint(
equalTo: centerXAnchor
).isActive = true
highlightView.centerYAnchor.constraint(
equalTo: centerYAnchor
).isActive = true
highlightView.widthAnchor.constraint(
equalTo: widthAnchor,
constant: -4
).isActive = true
highlightView.heightAnchor.constraint(
equalTo: heightAnchor,
constant: -2
).isActive = true
}

private func removeHighlightView() {
Expand Down Expand Up @@ -386,10 +408,7 @@ extension KeyRecorder {
didSet {
if failureReason.failureCount >= 3 {
recordingState = .idle
let alert = NSAlert()
alert.messageText = "Cannot record shortcut."
alert.informativeText = failureReason.message
alert.runModal()
failureReason.displayAlert()
failureReason = .noFailure
}
}
Expand Down Expand Up @@ -638,32 +657,44 @@ extension KeyRecorder.SegmentedControl {
case hasKeyCommand = "*****" // Should never be displayed
}

struct FailureReason: Equatable {
static let noFailure = Self(message: "There is nothing wrong.")
struct FailureReason {
static let noFailure = Self(infoText: "There is nothing wrong.")

static let needsModifiers = Self(message: """
static let needsModifiers = Self(infoText: """
Please include at least one modifier key \
(\([KeyCommand.Modifier].canonicalOrder.stringValue)).
""")

static let onlyShift = Self(message: """
\(KeyCommand.Modifier.shift.stringValue) by itself is not a valid \
modifier key. Please include at least one additional modifier key \
(\([KeyCommand.Modifier].canonicalOrder.stringValue)).
static let onlyShift = Self(infoText: """
Shift (\(KeyCommand.Modifier.shift.stringValue)) by itself is not a \
valid modifier key. Please include at least one additional modifier \
key (\([KeyCommand.Modifier].canonicalOrder.stringValue)).
""")

static func systemReserved(
key: KeyCommand.Key,
modifiers: [KeyCommand.Modifier]
) -> Self {
.init(
message: #""\#(modifiers.stringValue)\#(key.stringValue)" is reserved system-wide."#,
let settingsString = ProcessInfo.processInfo.isOperatingSystemAtLeast(
.init(
majorVersion: 13,
minorVersion: 0,
patchVersion: 0))
? "Settings"
: "Preferences"
return .init(
infoText: """
"\(modifiers.stringValue)\(key.stringValue)" \
is reserved system-wide. Most system shortcuts can be changed \
from "System \(settingsString) › Keyboard › Keyboard Shortcuts".
""",
failureCount: 3)
}

let message: String
let messageText: String
let infoText: String

var failureCount = 0 {
var failureCount: Int {
didSet {
guard
self == .noFailure,
Expand All @@ -675,13 +706,33 @@ extension KeyRecorder.SegmentedControl {
}
}

static func == (lhs: Self, rhs: Self) -> Bool {
lhs.message == rhs.message
init(
messageText: String = "Cannot record shortcut.",
infoText: String,
failureCount: Int = 0
) {
self.messageText = messageText
self.infoText = infoText
self.failureCount = failureCount
}

mutating func incrementFailureCount() {
failureCount += 1
}

func displayAlert() {
let alert = NSAlert()
alert.messageText = messageText
alert.informativeText = infoText
alert.runModal()
}
}
}

extension KeyRecorder.SegmentedControl.FailureReason: Equatable {
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.messageText == rhs.messageText &&
lhs.infoText == rhs.infoText
}
}

Expand Down

0 comments on commit da719c0

Please sign in to comment.