diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..35bb85d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +language: swift +xcode_project: MTMR.xcodeproj +xcode_scheme: UnitTests +osx_image: xcode9.3 +install: gem install xcpretty +script: "xcodebuild test -project MTMR.xcodeproj -scheme 'UnitTests' | xcpretty -c && exit ${PIPESTATUS[0]}" diff --git a/MTMR.xcodeproj/project.pbxproj b/MTMR.xcodeproj/project.pbxproj index 4aa24bc..a85279c 100644 --- a/MTMR.xcodeproj/project.pbxproj +++ b/MTMR.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 36300E83209F040900B31C71 /* SupportHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0008E542080286C003AD4DD /* SupportHelpers.swift */; }; + 36300E8F20A2CF3400B31C71 /* AppleScriptDefinitionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36300E8E20A2CF3400B31C71 /* AppleScriptDefinitionTests.swift */; }; + 36300E9120A2D2B200B31C71 /* BackgroundColorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36300E9020A2D2B200B31C71 /* BackgroundColorTests.swift */; }; 368EDDE720812A1D00E10953 /* ScrollViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 368EDDE620812A1D00E10953 /* ScrollViewItem.swift */; }; 36C2ECD7207B6DAE003CDA33 /* TimeTouchBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36C2ECD6207B6DAE003CDA33 /* TimeTouchBarItem.swift */; }; 36C2ECD9207B74B4003CDA33 /* AppleScriptTouchBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36C2ECD8207B74B4003CDA33 /* AppleScriptTouchBarItem.swift */; }; @@ -46,17 +49,10 @@ B0F8771A207AC1EA00D6E430 /* TouchBarSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = B0F87719207AC1EA00D6E430 /* TouchBarSupport.m */; }; /* End PBXBuildFile section */ -/* Begin PBXContainerItemProxy section */ - B082B262205C7D8000BC04DC /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = B082B247205C7D8000BC04DC /* Project object */; - proxyType = 1; - remoteGlobalIDString = B082B24E205C7D8000BC04DC; - remoteInfo = MTMR; - }; -/* End PBXContainerItemProxy section */ - /* Begin PBXFileReference section */ + 36300E85209FD16700B31C71 /* .travis.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .travis.yml; sourceTree = SOURCE_ROOT; }; + 36300E8E20A2CF3400B31C71 /* AppleScriptDefinitionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleScriptDefinitionTests.swift; sourceTree = ""; }; + 36300E9020A2D2B200B31C71 /* BackgroundColorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundColorTests.swift; sourceTree = ""; }; 368EDDE620812A1D00E10953 /* ScrollViewItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollViewItem.swift; sourceTree = ""; }; 36BDC22F207CDA8600FCFEBE /* TECHNICAL_DEBT.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = TECHNICAL_DEBT.md; sourceTree = ""; }; 36C2ECD2207B3B1D003CDA33 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; @@ -184,8 +180,11 @@ B082B264205C7D8000BC04DC /* MTMRTests */ = { isa = PBXGroup; children = ( + 36300E85209FD16700B31C71 /* .travis.yml */, 36C2ECDC207C723B003CDA33 /* ParseConfigTests.swift */, B082B267205C7D8000BC04DC /* Info.plist */, + 36300E8E20A2CF3400B31C71 /* AppleScriptDefinitionTests.swift */, + 36300E9020A2D2B200B31C71 /* BackgroundColorTests.swift */, ); path = MTMRTests; sourceTree = ""; @@ -266,7 +265,6 @@ buildRules = ( ); dependencies = ( - B082B263205C7D8000BC04DC /* PBXTargetDependency */, ); name = MTMRTests; productName = MTMRTests; @@ -378,21 +376,16 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 36300E9120A2D2B200B31C71 /* BackgroundColorTests.swift in Sources */, + 36300E8F20A2CF3400B31C71 /* AppleScriptDefinitionTests.swift in Sources */, 36C2ECDD207C723B003CDA33 /* ParseConfigTests.swift in Sources */, + 36300E83209F040900B31C71 /* SupportHelpers.swift in Sources */, 36C2ECDE207C82DE003CDA33 /* ItemsParsing.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXTargetDependency section */ - B082B263205C7D8000BC04DC /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = B082B24E205C7D8000BC04DC /* MTMR */; - targetProxy = B082B262205C7D8000BC04DC /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - /* Begin PBXVariantGroup section */ B082B258205C7D8000BC04DC /* Main.storyboard */ = { isa = PBXVariantGroup; diff --git a/MTMR.xcodeproj/xcshareddata/xcschemes/MTMR.xcscheme b/MTMR.xcodeproj/xcshareddata/xcschemes/MTMR.xcscheme new file mode 100644 index 0000000..97b1db9 --- /dev/null +++ b/MTMR.xcodeproj/xcshareddata/xcschemes/MTMR.xcscheme @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MTMR.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme b/MTMR.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme new file mode 100644 index 0000000..f5739de --- /dev/null +++ b/MTMR.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MTMR/CBridge/TouchBarSupport.m b/MTMR/CBridge/TouchBarSupport.m index dbd620a..6e92a5f 100644 --- a/MTMR/CBridge/TouchBarSupport.m +++ b/MTMR/CBridge/TouchBarSupport.m @@ -7,6 +7,7 @@ // #import "TouchBarSupport.h" +#import @implementation MediaKeys diff --git a/MTMR/ItemsParsing.swift b/MTMR/ItemsParsing.swift index c6115a5..4cfe593 100644 --- a/MTMR/ItemsParsing.swift +++ b/MTMR/ItemsParsing.swift @@ -229,7 +229,7 @@ enum ItemType: Decodable { enum ActionType: Decodable { case none - case hidKey(keycode: Int) + case hidKey(keycode: Int32) case keyPress(keycode: Int) case appleSctipt(source: SourceProtocol) case shellScript(executable: String, parameters: [String]) @@ -258,7 +258,7 @@ enum ActionType: Decodable { let type = try container.decodeIfPresent(ActionTypeRaw.self, forKey: .action) switch type { case .some(.hidKey): - let keycode = try container.decode(Int.self, forKey: .keycode) + let keycode = try container.decode(Int32.self, forKey: .keycode) self = .hidKey(keycode: keycode) case .some(.keyPress): let keycode = try container.decode(Int.self, forKey: .keycode) @@ -282,7 +282,7 @@ enum ActionType: Decodable { enum LongActionType: Decodable { case none - case hidKey(keycode: Int) + case hidKey(keycode: Int32) case keyPress(keycode: Int) case appleSctipt(source: SourceProtocol) case shellScript(executable: String, parameters: [String]) @@ -311,7 +311,7 @@ enum LongActionType: Decodable { let longType = try container.decodeIfPresent(LongActionTypeRaw.self, forKey: .longAction) switch longType { case .some(.hidKey): - let keycode = try container.decode(Int.self, forKey: .keycode) + let keycode = try container.decode(Int32.self, forKey: .keycode) self = .hidKey(keycode: keycode) case .some(.keyPress): let keycode = try container.decode(Int.self, forKey: .keycode) @@ -332,57 +332,6 @@ enum LongActionType: Decodable { } } -extension ItemType: Equatable {} -func ==(lhs: ItemType, rhs: ItemType) -> Bool { - switch (lhs, rhs) { - case let (.staticButton(a), .staticButton(b)): - return a == b - case let (.appleScriptTitledButton(a, b), .appleScriptTitledButton(c, d)): - return a == c && b == d - - default: - return false - } -} - -extension ActionType: Equatable {} -func ==(lhs: ActionType, rhs: ActionType) -> Bool { - switch (lhs, rhs) { - case (.none, .none): - return true - case let (.hidKey(a), .hidKey(b)), - let (.keyPress(a), .keyPress(b)): - return a == b - case let (.appleSctipt(a), .appleSctipt(b)): - return a == b - case let (.shellScript(a, b), .shellScript(c, d)): - return a == c && b == d - case let (.openUrl(a), .openUrl(b)): - return a == b - default: - return false - } -} - - -extension LongActionType: Equatable {} -func ==(lhs: LongActionType, rhs: LongActionType) -> Bool { - switch (lhs, rhs) { - case (.none, .none): - return true - case let (.hidKey(a), .hidKey(b)), - let (.keyPress(a), .keyPress(b)): - return a == b - case let (.appleSctipt(a), .appleSctipt(b)): - return a == b - case let (.shellScript(a, b), .shellScript(c, d)): - return a == c && b == d - case let (.openUrl(a), .openUrl(b)): - return a == b - default: - return false - } -} enum GeneralParameter { case width(_: CGFloat) @@ -468,10 +417,6 @@ extension NSImage: SourceProtocol { return self } } -extension SourceProtocol where Self: Equatable {} -func ==(left: SourceProtocol, right: SourceProtocol) -> Bool { - return left.data == right.data -} extension String { var base64Data: Data? { diff --git a/MTMR/KeyPress.swift b/MTMR/KeyPress.swift index fe0f109..23870dc 100644 --- a/MTMR/KeyPress.swift +++ b/MTMR/KeyPress.swift @@ -29,45 +29,24 @@ extension KeyPress { } } -func doKey(_ key: Int, down: Bool) { - let flags = NSEvent.ModifierFlags(rawValue: down ? 0xa00 : 0xb00) - let data1 = (key << 16) | ((down ? 0xa : 0xb) << 8) - - let ev = NSEvent.otherEvent( - with: NSEvent.EventType.systemDefined, - location: NSPoint(x:0.0, y:0.0), - modifierFlags: flags, +func doKey(_ key: UInt16, down: Bool) { + let ev = NSEvent.keyEvent( + with: down ? .keyDown : .keyUp, + location: .zero, + modifierFlags: [], timestamp: TimeInterval(0), windowNumber: 0, context: nil, - // context: 0, - subtype: 8, - data1: data1, - data2: -1 - ) + characters: "", + charactersIgnoringModifiers: "", + isARepeat: false, + keyCode: key) let cev = ev!.cgEvent! cev.post(tap: CGEventTapLocation(rawValue: 0)!) } -func HIDPostAuxKey(_ key: Int) { +func HIDPostAuxKey(_ key: Int32) { + let key = UInt16(key) doKey(key, down: true) doKey(key, down: false) } - - -// hidsystem/ev_keymap.h -let NX_KEYTYPE_SOUND_UP = 0 -let NX_KEYTYPE_SOUND_DOWN = 1 -let NX_KEYTYPE_MUTE = 7 - -let NX_KEYTYPE_BRIGHTNESS_UP = 2 -let NX_KEYTYPE_BRIGHTNESS_DOWN = 3 - -let NX_KEYTYPE_PLAY = 16 -let NX_KEYTYPE_NEXT = 17 -let NX_KEYTYPE_PREVIOUS = 18 - - - - - diff --git a/MTMR/SupportHelpers.swift b/MTMR/SupportHelpers.swift index 95a300c..a0a84f6 100644 --- a/MTMR/SupportHelpers.swift +++ b/MTMR/SupportHelpers.swift @@ -7,6 +7,7 @@ // import Foundation +import AppKit extension String { func trim() -> String { diff --git a/MTMRTests/AppleScriptDefinitionTests.swift b/MTMRTests/AppleScriptDefinitionTests.swift new file mode 100644 index 0000000..0977bab --- /dev/null +++ b/MTMRTests/AppleScriptDefinitionTests.swift @@ -0,0 +1,41 @@ +import XCTest + +class AppleScriptDefinitionTests: XCTestCase { + + func testInline() { + let buttonNoActionFixture = """ + [ { "type": "appleScriptTitledButton", "source": { "inline": "tell everything fine" } } ] + """.data(using: .utf8)! + let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonNoActionFixture) + guard case .appleScriptTitledButton(let source, _)? = result?.first?.type else { + XCTFail() + return + } + XCTAssertEqual(source.string, "tell everything fine") + } + + func testPath() { + let buttonNoActionFixture = """ + [ { "type": "appleScriptTitledButton", "source": { "filePath": "/ololo/pew" } } ] + """.data(using: .utf8)! + let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonNoActionFixture) + guard case .appleScriptTitledButton(let source, _)? = result?.first?.type else { + XCTFail() + return + } + let sourceStruct = source as? Source + XCTAssertEqual(sourceStruct?.filePath, "/ololo/pew") + } + + func testRefreshInterval() { + let buttonNoActionFixture = """ + [ { "type": "appleScriptTitledButton", "source": { "inline": "tell everything fine" }, "refreshInterval": 305} ] + """.data(using: .utf8)! + let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonNoActionFixture) + guard case .appleScriptTitledButton(_, 305)? = result?.first?.type else { + XCTFail() + return + } + } + +} diff --git a/MTMRTests/BackgroundColorTests.swift b/MTMRTests/BackgroundColorTests.swift new file mode 100644 index 0000000..915bbbc --- /dev/null +++ b/MTMRTests/BackgroundColorTests.swift @@ -0,0 +1,29 @@ +import XCTest + +class BackgroundColorTests: XCTestCase { + + func testOpaque() { + let buttonNoActionFixture = """ + [ { "type": "staticButton", "title": "Pew", "background": "#FF0000" } ] + """.data(using: .utf8)! + let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonNoActionFixture) + guard case .background(let color)? = result?.first?.additionalParameters[.background] else { + XCTFail() + return + } + XCTAssertEqual(color, .red) + } + + func testAlpha() { + let buttonNoActionFixture = """ + [ { "type": "staticButton", "title": "Pew", "background": "#FF000080" } ] + """.data(using: .utf8)! + let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonNoActionFixture) + guard case .background(let color)? = result?.first?.additionalParameters[.background] else { + XCTFail() + return + } + XCTAssertEqual(color.alphaComponent, 0.5, accuracy: 0.01) + } + +} diff --git a/MTMRTests/ParseConfigTests.swift b/MTMRTests/ParseConfigTests.swift index bd29393..f5e4221 100644 --- a/MTMRTests/ParseConfigTests.swift +++ b/MTMRTests/ParseConfigTests.swift @@ -1,5 +1,4 @@ import XCTest -@testable import MTMR class ParseConfig: XCTestCase { @@ -8,8 +7,14 @@ class ParseConfig: XCTestCase { [ { "type": "staticButton", "title": "Pew" } ] """.data(using: .utf8)! let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonNoActionFixture) - XCTAssertEqual(result?.first?.type, .staticButton(title: "Pew")) - XCTAssertEqual(result?.first?.action, .some(.none)) + guard case .staticButton("Pew")? = result?.first?.type else { + XCTFail() + return + } + guard case .none? = result?.first?.action else { + XCTFail() + return + } } func testButtonKeyCodeAction() { @@ -17,17 +22,48 @@ class ParseConfig: XCTestCase { [ { "type": "staticButton", "title": "Pew", "action": "hidKey", "keycode": 123} ] """.data(using: .utf8)! let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonKeycodeFixture) - XCTAssertEqual(result?.first?.type, .staticButton(title: "Pew")) - XCTAssertEqual(result?.first?.action, .hidKey(keycode: 123)) + guard case .staticButton("Pew")? = result?.first?.type else { + XCTFail() + return + } + guard case .hidKey(keycode: 123)? = result?.first?.action else { + XCTFail() + return + } } func testPredefinedItem() { let buttonKeycodeFixture = """ - [ { "type": "brightnessUp" } ] + [ { "type": "escape" } ] """.data(using: .utf8)! let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonKeycodeFixture) - XCTAssertEqual(result?.first?.type, .staticButton(title: "🔆")) - XCTAssertEqual(result?.first?.action, .keyPress(keycode: 113)) + guard case .staticButton("esc")? = result?.first?.type else { + XCTFail() + return + } + guard case .keyPress(keycode: 53)? = result?.first?.action else { + XCTFail() + return + } + } + + func testExtendedWidthForPredefinedItem() { + let buttonKeycodeFixture = """ + [ { "type": "escape", "width": 110}, ] + """.data(using: .utf8)! + let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonKeycodeFixture) + guard case .staticButton("esc")? = result?.first?.type else { + XCTFail() + return + } + guard case .keyPress(keycode: 53)? = result?.first?.action else { + XCTFail() + return + } + guard case .width(110)? = result?.first?.additionalParameters[.width] else { + XCTFail() + return + } } } diff --git a/README.md b/README.md index c4b54b5..8bfbd01 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ # My TouchBar. My rules [![GitHub release](https://img.shields.io/github/release/toxblh/MTMR.svg)](https://github.com/Toxblh/MTMR/releases) -[![license](https://img.shields.io/github/license/Toxblh/MTMR.svg)](https://github.com/Toxblh/MTMR/blob/master/LICENSE) [![Total downloads](https://img.shields.io/github/downloads/Toxblh/MTMR/total.svg)](https://github.com/Toxblh/MTMR/releases/latest) ![minimal system requirements](https://img.shields.io/badge/required-macOS%2010.12.2-blue.svg) +[![license](https://img.shields.io/github/license/Toxblh/MTMR.svg)](https://github.com/Toxblh/MTMR/blob/master/LICENSE) [![Total downloads](https://img.shields.io/github/downloads/Toxblh/MTMR/total.svg)](https://github.com/Toxblh/MTMR/releases/latest) ![minimal system requirements](https://img.shields.io/badge/required-macOS%2010.12.2-blue.svg) ![travis](https://travis-ci.org/Toxblh/MTMR.svg?branch=master)