Merge pull request #339 from olofhellman/master

Support for  ‘permalink’ and ‘external url’ properties of 'article'
This commit is contained in:
Brent Simmons 2018-02-11 10:49:22 -08:00 committed by GitHub
commit 668f614aad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 371 additions and 78 deletions

View File

@ -171,6 +171,17 @@
D5D1751220020B980047B29D /* Evergreen.sdef in Resources */ = {isa = PBXBuildFile; fileRef = D5D175012002039D0047B29D /* Evergreen.sdef */; }; D5D1751220020B980047B29D /* Evergreen.sdef in Resources */ = {isa = PBXBuildFile; fileRef = D5D175012002039D0047B29D /* Evergreen.sdef */; };
D5E4CC54202C1361009B4FFC /* AppDelegate+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5E4CC53202C1361009B4FFC /* AppDelegate+Scriptability.swift */; }; D5E4CC54202C1361009B4FFC /* AppDelegate+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5E4CC53202C1361009B4FFC /* AppDelegate+Scriptability.swift */; };
D5E4CC64202C1AC1009B4FFC /* MainWindowController+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5E4CC63202C1AC1009B4FFC /* MainWindowController+Scriptability.swift */; }; D5E4CC64202C1AC1009B4FFC /* MainWindowController+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5E4CC63202C1AC1009B4FFC /* MainWindowController+Scriptability.swift */; };
D5E4CCB320300024009B4FFC /* uiScriptingTestSetup.applescript in Sources */ = {isa = PBXBuildFile; fileRef = D5E4CCB220300024009B4FFC /* uiScriptingTestSetup.applescript */; };
D5E4CCB420300033009B4FFC /* uiScriptingTestSetup.applescript in CopyFiles */ = {isa = PBXBuildFile; fileRef = D5E4CCB220300024009B4FFC /* uiScriptingTestSetup.applescript */; };
D5E4CCC520300537009B4FFC /* AppleScriptXCTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5E4CCC3203004EA009B4FFC /* AppleScriptXCTestCase.swift */; };
D5E4CCD720303823009B4FFC /* selectAnArticle.applescript in Sources */ = {isa = PBXBuildFile; fileRef = D5E4CCD520303823009B4FFC /* selectAnArticle.applescript */; };
D5E4CCD820303823009B4FFC /* selectAFeed.applescript in Sources */ = {isa = PBXBuildFile; fileRef = D5E4CCD620303823009B4FFC /* selectAFeed.applescript */; };
D5E4CCDA2030382A009B4FFC /* establishMainWindowStartingState.applescript in Sources */ = {isa = PBXBuildFile; fileRef = D5E4CCD92030382A009B4FFC /* establishMainWindowStartingState.applescript */; };
D5E4CCDB20303A52009B4FFC /* selectAFeed.applescript in CopyFiles */ = {isa = PBXBuildFile; fileRef = D5E4CCD620303823009B4FFC /* selectAFeed.applescript */; };
D5E4CCDC20303A52009B4FFC /* selectAnArticle.applescript in CopyFiles */ = {isa = PBXBuildFile; fileRef = D5E4CCD520303823009B4FFC /* selectAnArticle.applescript */; };
D5E4CCDD20303A59009B4FFC /* establishMainWindowStartingState.applescript in CopyFiles */ = {isa = PBXBuildFile; fileRef = D5E4CCD92030382A009B4FFC /* establishMainWindowStartingState.applescript */; };
D5E4CCDE20303A66009B4FFC /* testCurrentArticleIsNil.applescript in CopyFiles */ = {isa = PBXBuildFile; fileRef = D5E4CCD12030260E009B4FFC /* testCurrentArticleIsNil.applescript */; };
D5E4CCDF20303A66009B4FFC /* testURLsOfCurrentArticle.applescript in CopyFiles */ = {isa = PBXBuildFile; fileRef = D5E4CCCF203025FF009B4FFC /* testURLsOfCurrentArticle.applescript */; };
D5F4EDB5200744A700B9E363 /* ScriptingObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB4200744A700B9E363 /* ScriptingObject.swift */; }; D5F4EDB5200744A700B9E363 /* ScriptingObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB4200744A700B9E363 /* ScriptingObject.swift */; };
D5F4EDB720074D6500B9E363 /* Feed+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB620074D6500B9E363 /* Feed+Scriptability.swift */; }; D5F4EDB720074D6500B9E363 /* Feed+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB620074D6500B9E363 /* Feed+Scriptability.swift */; };
D5F4EDB920074D7C00B9E363 /* Folder+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */; }; D5F4EDB920074D7C00B9E363 /* Folder+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */; };
@ -485,6 +496,12 @@
dstPath = TestScripts; dstPath = TestScripts;
dstSubfolderSpec = 7; dstSubfolderSpec = 7;
files = ( files = (
D5E4CCDE20303A66009B4FFC /* testCurrentArticleIsNil.applescript in CopyFiles */,
D5E4CCDF20303A66009B4FFC /* testURLsOfCurrentArticle.applescript in CopyFiles */,
D5E4CCDD20303A59009B4FFC /* establishMainWindowStartingState.applescript in CopyFiles */,
D5E4CCDB20303A52009B4FFC /* selectAFeed.applescript in CopyFiles */,
D5E4CCDC20303A52009B4FFC /* selectAnArticle.applescript in CopyFiles */,
D5E4CCB420300033009B4FFC /* uiScriptingTestSetup.applescript in CopyFiles */,
D5A267C220131BA000A8D3C0 /* testFeedOPML.applescript in CopyFiles */, D5A267C220131BA000A8D3C0 /* testFeedOPML.applescript in CopyFiles */,
D5A2679D201313A200A8D3C0 /* testNameOfAuthors.applescript in CopyFiles */, D5A2679D201313A200A8D3C0 /* testNameOfAuthors.applescript in CopyFiles */,
D5F4EDE920075C6700B9E363 /* testNameAndUrlOfEveryFeed.applescript in CopyFiles */, D5F4EDE920075C6700B9E363 /* testNameAndUrlOfEveryFeed.applescript in CopyFiles */,
@ -664,6 +681,13 @@
D5D175012002039D0047B29D /* Evergreen.sdef */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = Evergreen.sdef; path = ../Resources/Evergreen.sdef; sourceTree = "<group>"; }; D5D175012002039D0047B29D /* Evergreen.sdef */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = Evergreen.sdef; path = ../Resources/Evergreen.sdef; sourceTree = "<group>"; };
D5E4CC53202C1361009B4FFC /* AppDelegate+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Scriptability.swift"; sourceTree = "<group>"; }; D5E4CC53202C1361009B4FFC /* AppDelegate+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Scriptability.swift"; sourceTree = "<group>"; };
D5E4CC63202C1AC1009B4FFC /* MainWindowController+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainWindowController+Scriptability.swift"; sourceTree = "<group>"; }; D5E4CC63202C1AC1009B4FFC /* MainWindowController+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainWindowController+Scriptability.swift"; sourceTree = "<group>"; };
D5E4CCB220300024009B4FFC /* uiScriptingTestSetup.applescript */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.applescript; path = uiScriptingTestSetup.applescript; sourceTree = "<group>"; };
D5E4CCC3203004EA009B4FFC /* AppleScriptXCTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppleScriptXCTestCase.swift; path = EvergreenTests/ScriptingTests/AppleScriptXCTestCase.swift; sourceTree = SOURCE_ROOT; };
D5E4CCCF203025FF009B4FFC /* testURLsOfCurrentArticle.applescript */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.applescript; path = testURLsOfCurrentArticle.applescript; sourceTree = "<group>"; };
D5E4CCD12030260E009B4FFC /* testCurrentArticleIsNil.applescript */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.applescript; path = testCurrentArticleIsNil.applescript; sourceTree = "<group>"; };
D5E4CCD520303823009B4FFC /* selectAnArticle.applescript */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.applescript; path = selectAnArticle.applescript; sourceTree = "<group>"; };
D5E4CCD620303823009B4FFC /* selectAFeed.applescript */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.applescript; path = selectAFeed.applescript; sourceTree = "<group>"; };
D5E4CCD92030382A009B4FFC /* establishMainWindowStartingState.applescript */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.applescript; path = establishMainWindowStartingState.applescript; sourceTree = "<group>"; };
D5F4EDB4200744A700B9E363 /* ScriptingObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptingObject.swift; sourceTree = "<group>"; }; D5F4EDB4200744A700B9E363 /* ScriptingObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptingObject.swift; sourceTree = "<group>"; };
D5F4EDB620074D6500B9E363 /* Feed+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Feed+Scriptability.swift"; sourceTree = "<group>"; }; D5F4EDB620074D6500B9E363 /* Feed+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Feed+Scriptability.swift"; sourceTree = "<group>"; };
D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Folder+Scriptability.swift"; sourceTree = "<group>"; }; D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Folder+Scriptability.swift"; sourceTree = "<group>"; };
@ -1281,6 +1305,7 @@
children = ( children = (
D5558FCF20021C590066386B /* scripts */, D5558FCF20021C590066386B /* scripts */,
D5558FD22002245C0066386B /* ScriptingTests.swift */, D5558FD22002245C0066386B /* ScriptingTests.swift */,
D5E4CCC3203004EA009B4FFC /* AppleScriptXCTestCase.swift */,
); );
path = ScriptingTests; path = ScriptingTests;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1288,6 +1313,9 @@
D5558FCF20021C590066386B /* scripts */ = { D5558FCF20021C590066386B /* scripts */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D5E4CCD92030382A009B4FFC /* establishMainWindowStartingState.applescript */,
D5E4CCD620303823009B4FFC /* selectAFeed.applescript */,
D5E4CCD520303823009B4FFC /* selectAnArticle.applescript */,
D5907C9D20023249005947E5 /* testGenericScript.applescript */, D5907C9D20023249005947E5 /* testGenericScript.applescript */,
D5A267B220131B8300A8D3C0 /* testFeedOPML.applescript */, D5A267B220131B8300A8D3C0 /* testFeedOPML.applescript */,
D5558FD1200223F60066386B /* testGetURL.applescript */, D5558FD1200223F60066386B /* testGetURL.applescript */,
@ -1295,6 +1323,9 @@
D5A2679B201312F900A8D3C0 /* testNameOfAuthors.applescript */, D5A2679B201312F900A8D3C0 /* testNameOfAuthors.applescript */,
D5F4EDD720075C1300B9E363 /* testNameOfEveryFolder.applescript */, D5F4EDD720075C1300B9E363 /* testNameOfEveryFolder.applescript */,
D55373A02018797B006D8857 /* testTitleOfArticlesWhose.applescript */, D55373A02018797B006D8857 /* testTitleOfArticlesWhose.applescript */,
D5E4CCD12030260E009B4FFC /* testCurrentArticleIsNil.applescript */,
D5E4CCCF203025FF009B4FFC /* testURLsOfCurrentArticle.applescript */,
D5E4CCB220300024009B4FFC /* uiScriptingTestSetup.applescript */,
); );
path = scripts; path = scripts;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1952,10 +1983,15 @@
D5A267C120131B8300A8D3C0 /* testFeedOPML.applescript in Sources */, D5A267C120131B8300A8D3C0 /* testFeedOPML.applescript in Sources */,
D5A2679C201312F900A8D3C0 /* testNameOfAuthors.applescript in Sources */, D5A2679C201312F900A8D3C0 /* testNameOfAuthors.applescript in Sources */,
849C64761ED37A5D003D8FC0 /* EvergreenTests.swift in Sources */, 849C64761ED37A5D003D8FC0 /* EvergreenTests.swift in Sources */,
D5E4CCC520300537009B4FFC /* AppleScriptXCTestCase.swift in Sources */,
D5E4CCB320300024009B4FFC /* uiScriptingTestSetup.applescript in Sources */,
D5558FD32002245C0066386B /* ScriptingTests.swift in Sources */, D5558FD32002245C0066386B /* ScriptingTests.swift in Sources */,
D5E4CCDA2030382A009B4FFC /* establishMainWindowStartingState.applescript in Sources */,
D5F4EDE820075C1800B9E363 /* testNameAndUrlOfEveryFeed.applescript in Sources */, D5F4EDE820075C1800B9E363 /* testNameAndUrlOfEveryFeed.applescript in Sources */,
D5907CA0200232A1005947E5 /* testGenericScript.applescript in Sources */, D5907CA0200232A1005947E5 /* testGenericScript.applescript in Sources */,
D5F4EDE620075C1300B9E363 /* testNameOfEveryFolder.applescript in Sources */, D5F4EDE620075C1300B9E363 /* testNameOfEveryFolder.applescript in Sources */,
D5E4CCD720303823009B4FFC /* selectAnArticle.applescript in Sources */,
D5E4CCD820303823009B4FFC /* selectAFeed.applescript in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

View File

@ -139,9 +139,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
feedIconDownloader = FeedIconDownloader(imageDownloader: imageDownloader) feedIconDownloader = FeedIconDownloader(imageDownloader: imageDownloader)
updateSortMenuItems() updateSortMenuItems()
createAndShowMainWindow() createAndShowMainWindow()
installAppleEventHandlers()
NSAppleEventManager.shared().setEventHandler(self, andSelector: #selector(AppDelegate.getURL(_:_:)), forEventClass: AEEventClass(kInternetEventClass), andEventID: AEEventID(kAEGetURL))
NotificationCenter.default.addObserver(self, selector: #selector(feedSettingDidChange(_:)), name: .FeedSettingDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(feedSettingDidChange(_:)), name: .FeedSettingDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange(_:)), name: UserDefaults.didChangeNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange(_:)), name: UserDefaults.didChangeNotification, object: nil)
@ -185,25 +184,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
saveState() saveState()
} }
// MARK: GetURL Apple Event
@objc func getURL(_ event: NSAppleEventDescriptor, _ withReplyEvent: NSAppleEventDescriptor) {
guard let urlString = event.paramDescriptor(forKeyword: keyDirectObject)?.stringValue else {
return
}
let normalizedURLString = urlString.rs_normalizedURL()
if !normalizedURLString.rs_stringMayBeURL() {
return
}
DispatchQueue.main.async {
self.addFeed(normalizedURLString)
}
}
// MARK: Notifications // MARK: Notifications
@objc func unreadCountDidChange(_ note: Notification) { @objc func unreadCountDidChange(_ note: Notification) {

View File

@ -6,6 +6,13 @@
<dictionary title="sa;lfsdf" xmlns:xi="http://www.w3.org/2003/XInclude"> <dictionary title="sa;lfsdf" xmlns:xi="http://www.w3.org/2003/XInclude">
<suite name="Standard Suite" code="core" description="Subset of the Standard Suite."> <suite name="Standard Suite" code="core" description="Subset of the Standard Suite.">
<access-group identifier="com.ranchero.Evergreen" access="rw"/>
<command name="exists" code="coredoex" description="Verify that an object exists.">
<cocoa class="Evergreen.EvergreenExistsCommand"/>
<direct-parameter type="any" requires-access="r" description="The object(s) to check."/>
<result type="boolean" description="Does the object(s) exist?"/>
</command>
<class name="application" code="capp" description="The application's top-level scripting object."> <class name="application" code="capp" description="The application's top-level scripting object.">
<cocoa class="NSApplication"/> <cocoa class="NSApplication"/>
<property name="name" code="pnam" type="text" access="r" description="The name of the application."/> <property name="name" code="pnam" type="text" access="r" description="The name of the application."/>
@ -14,6 +21,7 @@
</suite> </suite>
<suite name="Evergreen Suite" code="Geod" description="The Evergreen Application Suite."> <suite name="Evergreen Suite" code="Geod" description="The Evergreen Application Suite.">
<access-group identifier="com.ranchero.Evergreen" access="rw"/>
<class name="application" code="capp" <class name="application" code="capp"
description="Evergreen Application" inherits="application"> description="Evergreen Application" inherits="application">
@ -142,9 +150,15 @@
<property name="title" code="titl" type="text" access="r" description="The article title"> <property name="title" code="titl" type="text" access="r" description="The article title">
<cocoa key="title"/> <cocoa key="title"/>
</property> </property>
<property name="url" code="URL " type="text" access="r" description="url for the article"> <property name="url" code="URL " type="text" access="r" description="url for the article. This will be the permalink if available, or the external url">
<cocoa key="url"/> <cocoa key="url"/>
</property> </property>
<property name="external url" code="eURL" type="text" access="r" description="the external url for the article, if known">
<cocoa key="externalUrl"/>
</property>
<property name="permalink" code="pLnk" type="text" access="r" description="a permalink for the article, if known">
<cocoa key="permalink"/>
</property>
<property name="contents" code="Cnts" type="text" access="r" description="text of the article"> <property name="contents" code="Cnts" type="text" access="r" description="text of the article">
<cocoa key="contents"/> <cocoa key="contents"/>
</property> </property>
@ -182,9 +196,9 @@
</suite> </suite>
<suite name="Internet Suite" code="GURL" <suite name="Internet Suite" code="GURL" description="Standard Internet Suite.">
description="Standard Internet Suite."> <access-group identifier="com.ranchero.Evergreen" access="rw"/>
<command name="open location" code="GURLGURL" description="opens the given url."> <command name="open location" code="GURLGURL" description="opens the given url.">
<direct-parameter type="text"/> <direct-parameter type="text"/>
</command> </command>

View File

@ -19,10 +19,60 @@
import Foundation import Foundation
import Data import Data
protocol AppDelegateAppleEvents {
func installAppleEventHandlers()
func getURL(_ event: NSAppleEventDescriptor, _ withReplyEvent: NSAppleEventDescriptor)
}
protocol ScriptingAppDelegate { protocol ScriptingAppDelegate {
var scriptingCurrentArticle: Article? {get} var scriptingCurrentArticle: Article? {get}
var scriptingSelectedArticles: [Article] {get} var scriptingSelectedArticles: [Article] {get}
var scriptingMainWindowController:ScriptingMainWindowController? {get} var scriptingMainWindowController:ScriptingMainWindowController? {get}
} }
extension AppDelegate : AppDelegateAppleEvents {
// MARK: GetURL Apple Event
func installAppleEventHandlers() {
NSAppleEventManager.shared().setEventHandler(self, andSelector: #selector(AppDelegate.getURL(_:_:)), forEventClass: AEEventClass(kInternetEventClass), andEventID: AEEventID(kAEGetURL))
}
@objc func getURL(_ event: NSAppleEventDescriptor, _ withReplyEvent: NSAppleEventDescriptor) {
guard let urlString = event.paramDescriptor(forKeyword: keyDirectObject)?.stringValue else {
return
}
let normalizedURLString = urlString.rs_normalizedURL()
if !normalizedURLString.rs_stringMayBeURL() {
return
}
DispatchQueue.main.async {
self.addFeed(normalizedURLString)
}
}
}
class EvergreenExistsCommand : NSExistsCommand {
// cocoa default behavior doesn't work here, because of cases where we define an object's property
// to be another object type. e.g., 'permalink of the current article' parses as
// <property> of <property> of <top level object>
// cocoa would send the top level object (the app) a doesExist message for a nested property, and
// it errors out because it doesn't know how to handle that
// What we do instead is simply see if the defaultImplementation errors, and if it does, the object
// must not exist. Otherwise, we return the result of the defaultImplementation
// The wrinkle is that it is possible that the direct object is a list, so we need to
// handle that case as well
override func performDefaultImplementation() -> Any? {
guard let result = super.performDefaultImplementation() else { return NSNumber(booleanLiteral:false) }
return result
// return NSNumber(booleanLiteral:true)
// scriptingContainer.handleDoObjectsExist(command:self)
}
}

View File

@ -51,10 +51,20 @@ class ScriptableArticle: NSObject, UniqueIdScriptingObject, ScriptingObjectConta
// MARK: --- Scriptable properties --- // MARK: --- Scriptable properties ---
@objc(url) @objc(url)
var url:String { var url:String? {
return article.url ?? "" return article.url ?? article.externalURL
} }
@objc(permalink)
var permalink:String? {
return article.url
}
@objc(externalUrl)
var externalUrl:String? {
return article.externalURL
}
@objc(uniqueId) @objc(uniqueId)
var uniqueId:String { var uniqueId:String {
return article.uniqueID return article.uniqueID

View File

@ -12,9 +12,8 @@ protocol ScriptingObjectContainer: ScriptingObject {
var scriptingClassDescription:NSScriptClassDescription { get } var scriptingClassDescription:NSScriptClassDescription { get }
} }
extension ScriptingObjectContainer { extension ScriptingObjectContainer {
func makeFormNameScriptObjectSpecifier(forObject object:NamedScriptingObject) -> NSScriptObjectSpecifier? { func makeFormNameScriptObjectSpecifier(forObject object:NamedScriptingObject) -> NSScriptObjectSpecifier? {
let containerClassDescription = self.scriptingClassDescription let containerClassDescription = self.scriptingClassDescription
let containerScriptObjectSpecifier = self.objectSpecifier let containerScriptObjectSpecifier = self.objectSpecifier

View File

@ -0,0 +1,67 @@
//
// AppleScriptXCTestCase.swift
// EvergreenUITests
//
// Created by Olof Hellman on 2/10/18.
// Copyright © 2018 Ranchero Software. All rights reserved.
//
import XCTest
class AppleScriptXCTestCase: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
/*
@function doIndividualScript
@param filename -- name of a .applescript (sans extention) in the test bundle's
Resources/TestScripts directory
@brief given a file, loads the script and runs it. Expects a result from running
the script of the form
{test_result:true, script_result:<anything>}
if the test_result is false or is missing, the test fails
@return the value of script_result, if any
*/
func doIndividualScript(filename:String) -> NSAppleEventDescriptor? {
var errorDict: NSDictionary? = nil
let testBundle = Bundle(for: type(of: self))
let url = testBundle.url(forResource:filename, withExtension:"applescript", subdirectory:"TestScripts")
guard let testScriptUrl = url else {
XCTFail("Failed Getting script URL")
return nil
}
guard let testScript = NSAppleScript(contentsOf: testScriptUrl, error: &errorDict) else {
print ("error is \(String(describing: errorDict))")
XCTFail("Failed initializing NSAppleScript")
return nil
}
let scriptResult = testScript.executeAndReturnError(&errorDict)
if (errorDict != nil) {
print ("error is \(String(describing: errorDict))")
XCTFail("Failed executing script")
return nil
}
let usrfDictionary = scriptResult.usrfDictionary()
guard let testResult = usrfDictionary["test_result"] else {
XCTFail("test script didn't return test result in usrf")
return nil
}
if (testResult.booleanValue != true) {
print("test_result was \(testResult)")
print("script_result was \(String(describing: usrfDictionary["script_result"]))")
}
XCTAssert(testResult.booleanValue == true, "test_result should be true")
return usrfDictionary["script_result"]
}
}

View File

@ -8,7 +8,7 @@
import XCTest import XCTest
class ScriptingTests: XCTestCase { class ScriptingTests: AppleScriptXCTestCase {
override func setUp() { override func setUp() {
super.setUp() super.setUp()
@ -18,52 +18,6 @@ class ScriptingTests: XCTestCase {
super.tearDown() super.tearDown()
} }
/*
@function doIndividualScript
@param filename -- name of a .applescript (sans extention) in the test bundle's
Resources/TestScripts directory
@brief given a file, loads the script and runs it. Expects a result from running
the script of the form
{test_result:true, script_result:<anything>}
if the test_result is false or is missing, the test fails
@return the value of script_result, if any
*/
func doIndividualScript(filename:String) -> NSAppleEventDescriptor? {
var errorDict: NSDictionary? = nil
let testBundle = Bundle(for: type(of: self))
let url = testBundle.url(forResource:filename, withExtension:"applescript", subdirectory:"TestScripts")
guard let testScriptUrl = url else {
XCTFail("Failed Getting script URL")
return nil
}
guard let testScript = NSAppleScript(contentsOf: testScriptUrl, error: &errorDict) else {
XCTFail("Failed initializing NSAppleScript")
print ("error is \(String(describing: errorDict))")
return nil
}
let scriptResult = testScript.executeAndReturnError(&errorDict)
if (errorDict != nil) {
XCTFail("Failed executing script")
print ("error is \(String(describing: errorDict))")
return nil
}
let usrfDictionary = scriptResult.usrfDictionary()
guard let testResult = usrfDictionary["test_result"] else {
XCTFail("test script didn't return test result in usrf")
return nil
}
XCTAssert(testResult.booleanValue == true, "test_result should be true")
if (testResult.booleanValue != true )
{
print("test_result was \(testResult)")
print("script_result was \(String(describing: usrfDictionary["script_result"]))")
}
return usrfDictionary["script_result"]
}
/* /*
@function testGenericScript @function testGenericScript
@ -102,4 +56,32 @@ class ScriptingTests: XCTestCase {
_ = doIndividualScript(filename: "testTitleOfArticlesWhose") _ = doIndividualScript(filename: "testTitleOfArticlesWhose")
} }
func doIndividualScriptWithExpectation(filename:String) {
let queue = DispatchQueue(label:"testQueue")
let scriptExpectation = self.expectation(description: filename+"expectation")
queue.async {
_ = self.doIndividualScript(filename:filename)
scriptExpectation.fulfill()
}
self.wait(for:[scriptExpectation], timeout:60)
}
/*
@function testCurrentArticleScripts
@brief the pices of the test are broken up into smaller pieces because of the
way events are delivered to the app -- I tried one single script with all the
actions and the keystrokes aren't delivered to the app right away, so the ui
isn't updated in time for 'current article' to be set. But, breaking them up
in this way seems to work.
*/
func testCurrentArticleScripts() {
doIndividualScriptWithExpectation(filename: "uiScriptingTestSetup")
doIndividualScriptWithExpectation(filename: "establishMainWindowStartingState")
doIndividualScriptWithExpectation(filename: "selectAFeed")
doIndividualScriptWithExpectation(filename: "testCurrentArticleIsNil")
doIndividualScriptWithExpectation(filename: "selectAnArticle")
doIndividualScriptWithExpectation(filename: "testURLsOfCurrentArticle")
}
} }

View File

@ -0,0 +1,37 @@
property uparrowKeyCode : 126
property downarrowKeyCode : 125
property rightarrowKeyCode : 124
property leftarrowKeyCode : 123
to activateEvergreen()
tell application "Evergreen"
activate
end tell
end activateEvergreen
to multipleKeyCodes(keycode, numberOfKeys)
tell application "System Events"
tell process "Evergreen"
repeat numberOfKeys times
key code keycode
end repeat
end tell
end tell
end multipleKeyCodes
to establishMainWindowStartingState()
activateEvergreen()
multipleKeyCodes(downarrowKeyCode, 2)
multipleKeyCodes(rightarrowKeyCode, 2)
multipleKeyCodes(leftarrowKeyCode, 2)
multipleKeyCodes(uparrowKeyCode, 50)
end establishMainWindowStartingState
try
establishMainWindowStartingState()
-- hit the down arrow a few times to get into the feeds
on error message
return {test_result:false, script_result:message}
end try
return {test_result:true, script_result:"established starting state"}

View File

@ -0,0 +1,32 @@
property uparrowKeyCode : 126
property downarrowKeyCode : 125
property rightarrowKeyCode : 124
property leftarrowKeyCode : 123
to activateEvergreen()
tell application "Evergreen"
activate
end tell
end activateEvergreen
to multipleKeyCodes(keycode, numberOfKeys)
tell application "System Events"
tell process "Evergreen"
repeat numberOfKeys times
key code keycode
end repeat
end tell
end tell
end multipleKeyCodes
try
activateEvergreen()
multipleKeyCodes(downarrowKeyCode, 9)
multipleKeyCodes(uparrowKeyCode, 1)
on error message
return {test_result:false, script_result:message}
end try
return {test_result:true, script_result:"selected feed"}

View File

@ -0,0 +1,31 @@
property uparrowKeyCode : 126
property downarrowKeyCode : 125
property rightarrowKeyCode : 124
property leftarrowKeyCode : 123
to activateEvergreen()
tell application "Evergreen"
activate
end tell
end activateEvergreen
to multipleKeyCodes(keycode, numberOfKeys)
tell application "System Events"
tell process "Evergreen"
repeat numberOfKeys times
key code keycode
end repeat
end tell
end tell
end multipleKeyCodes
try
activateEvergreen()
multipleKeyCodes(rightarrowKeyCode, 1)
on error message
return {test_result:false, script_result:message}
end try
return {test_result:true, script_result:"selected an article"}

View File

@ -0,0 +1,23 @@
-- this script tests that it is possible to get the url property of the current article
-- it uses system event accessibility scripting to set up the main window
-- one needs to authorize scripting accessibility control in the System Preferences'
-- Privacy and security pane
try
tell application "Evergreen"
set shouldBeMissingValue to current article
end tell
--verify that the current article is in fact 'missing vcalue'
if shouldBeMissingValue is missing value then
set the_message to "passed tests"
set the_result to true
else
set the_message to "expected current article to be 'missing value'"
set the_result to false
end if
on error message
return {test_result:false, script_result:message}
end try
return {test_result:the_result, script_result:the_message}

View File

@ -0,0 +1,14 @@
-- this script tests that it is possible to get the url property of the current article
-- it uses system event accessibility scripting to set up the main window
-- one needs to authorize scripting accessibility control in the System Preferences'
-- Privacy and security pane
try
tell application "Evergreen"
{url, permalink, external url} of current article
end tell
on error message
return {test_result:false, script_result:message}
end try
return {test_result:true, script_result:"tests passed"}

View File

@ -0,0 +1,18 @@
-- this script sets up Evergreen so it is ready to be tested
-- to get a current article
to activateEvergreen()
tell application "Evergreen"
activate
end tell
end activateEvergreen
tell application "System Events"
set isFrontmost to frontmost of process "Evergreen"
repeat while isFrontmost is false
my activateEvergreen()
set isFrontmost to frontmost of process "Evergreen"
end repeat
end tell
return {test_result:true, script_result:"finished"}