|
|
| View previous topic :: View next topic |
| Author |
Message |
Todd AuberGenie

Joined: 20 Jan 2007 Posts: 265
|
Posted: Tue Oct 09, 2007 2:35 am Post subject: Typing text to a hand held device's telephone style keypad.. |
|
|
I've been out on the road visiting with folks using Eggplant from the East to the West coasts. Some of our friends are developing or have in market mobile devices in need of GUI testing.
One in particular is the Nokia N95 (http://www.nseries.com/index.html) running the S60 (http://www.s60.com/life) operating system. With mVNC installed to do VNC <-> bluetooth stack translations, this little device and operating system are prime candidates for device automation and testing.
To make it easy to test contact information, a simple script was created for our friends in Europe testing this configuration to reduce the tedium of typing characters from a standard telephone's numeric pad. An example of how you may not want a script to look due to the difficult way it reads may be considered:
As you can see, there quite a few sequences to just punch in a simple name. Why not allow Eggplant and its embedded scripting language Sensetalk along with some thought take the choir out of the task. A powerful idea like repeat looping gives the power take redundant tasks like testing and compress ideas into a series of values or in this case mappings of values. Embedding the keys, and how they are to be mapped to the keypad of a mobile phone is a simple process yet one that needs some thought.
| Code: | -- Take a set of values and map to keys in a property list
set keypad to ( a:(2,1), b:(2,2), c:(2,3), \
d:(3,1), e:(3,2), f:(3,3), \
g:(4,1), h:(4,2), i:(4,3), \
j:(5,1), k:(5,2), l:(5,3), \
m:(6,1), n:(6,2), o:(6,3), \
p:(7,1), q:(7,2), r:(7,3), s:(7,4), \
t:(8,1), u:(8,2), v:(8,3), \
w:(9,1), x:(9,2), y:(9,3), z:(9,4), \
" ":("#", 1))
|
Each character of the alphabet and a few special keys are handled in this simple SenseTalk Property List. Allowing for simple lookup by character, we also have as the property value a list which is the phone pad numeric key to type and it's count. For instance, to type on the remote mobile device the capital letter "A" the following SenseTalk script will output "01".
| Code: | repeat with each item aKey in keys
repeat with each char aChar in aKey
repeat item 2 of keypad.(aChar) times
if aChar is an uppercase then TypeText 0
TypeText item 1 of keypad.(aChar)
end repeat
end repeat
end repeat
|
So, simply each character in the variable keys is swept, we look up the value in the property list, we then use that key to get the count (item 2) and if the character is an upper case letter the "0" is punched so capitalization results. Please remember when reading SenseTalk script, parenthetical notation is used to reference the actual value in a variable rather than as an unquoted literal referencing a particular key as a string. This point is one of the biggest pitfalls with experienced and new users alike and one of the most likely places for errors to occur in scripts.
We also want to slow down the RemoteWorkInterval to make the characters seem as if someone was punching on the device with their thumbs. There is no need to set the RWI down to less than .25 as a human would be very hard pressed (no pun intended) to type more than 4 chars per second, or about 240 chars per min on a device regularly. If turned down to 0.1, a dual thumbed user would be typing 600 chars per minute, or about 100 words per minute without errors. This is based on the average english word length of approximately six characters including a space of separation. This is simply not possible by even highly trained people using QWERTY keyboards, common enough on DVORAK, and definitely nearly if not impossible on a two thumb device.
| Code: | params n, keys...
if n is not a positive number then
insert n before keys
set n to .25 seconds
end if
set orwi to the RemoteWorkInterval
set the RemoteWorkInterval to n
|
Its good form/style and courtesy to Eggplant's global values the way you found them if altering for speed and performance issues during script execution. Please find another posting describing the ins and outs of the StoreEggplantSettings and RestoreEggplantSettings scripts included in this project.
And finally, the result allows a more readable form to be used when typing text to a remote mobile device.
| Code: | TypePhoneKey "Todd Nathan"
TypePhoneKey "Support Services Manager"
|
which will in this case instruct the mVNC server to output
| Code: | 0866633#06062844266
0707070788776667778#0707070733777
888444222337777#062662433777 |
| Description: |
| Download, unpackage, drag and drop as a helper suite. |
|
 Download |
| Filename: |
MobilityLibrary.suite.zip |
| Filesize: |
28.33 KB |
| Downloaded: |
973 Time(s) |
|
|
| Back to top |
|
 |
Todd AuberGenie

Joined: 20 Jan 2007 Posts: 265
|
Posted: Thu Oct 11, 2007 11:31 am Post subject: Eggplant State Management |
|
|
In some previous posts I have discussed a need for generalized solutions to changing values of state in the Eggplant global variable environments. Generally a push/pop approach to state change works allowing someone to quickly store/restore value sets. We offer to you a simple Last-In-First-Out approach which can be viewed as a stack of dinner plates of which the topmost 'plate' holds the entire set of keys and values of your Eggplant environment. Below is a demonstration Main.script and the supporting StoreEggplantProperties/RestoreEggplantProperties scripts.
| Code: | (**
Start state: SUT, OS X FUS 10.4.10 w/HD icon unselected
Eggplant, MouseDragSpeed = 0 for 'instant' moves
**)
MoveHardDriveIcon (300,300) -- drag speed set to zero.
StoreEggplantProperties -- for restoration later.
set the mouseDragSpeed to 1 -- slow the drag down
MoveHardDriveIcon -- visible drag speed...
RestoreEggplantProperties -- reset to last EP settings.
MoveHardDriveIcon -- move at speed restored.
|
The MoveHardDriveIcon needs little explanation, it moves the first found Hard Drive icon from its current location to a point provided as an optional parameter, or ( 100, 100 ) if a valid point is not provided. Of course this is for demonstration purposes, and likely would rather have it toss an exception if a non valid point is provided.
The process of storing every single Eggplant setting is a little tedious. Discover and description of each setting is located and clear in the Eggplant Referenence manual. For ease of reading, each section of the preferences settings panes has been defined in a seperate list, then combined in AllSettings as a list. Each item is then used as a key in the dynamic construction of a property list of name value pairs. This is inserted into the end of the universal variable EggplantPropertyList which is in turn used by the complimentary and accurately named RestoreEggplantProperties handler.
| Code: | -- The meat and potatoes of the storage process.
repeat with each item aSetting in AllSettings
set EggplantPropertyList.(aSetting) to the ( aSetting )
end repeat
insert EggplantPropertyList into EggplantPropertyLists
|
And finally the core of the restoration process (see the accompany download suite for the entire scripts) which reads the last item of the EggplantPropertyList variable and uses that property list to restore Eggplant to a previously stored state.
| Code: | -- Core loop for Eggplant restoration from a property list
repeat with each key in the keys of anEggplantPropertyList
set the ( key ) to anEggplantPropertyList.(key)
end repeat
delete last item in EggplantPropertyLists -- remove it
|
NOTE: although this was demonstrated in Main.script against an OS X SUT, you can use this set of scripts with any SUT system.
Left as a "Reader Challenge", you may desire to expand the RestoreEggplantProperties handler script to allow the passing of a positive numerical value indicating which state of the LIFO Eggplant state stack is used during restoration and then subsequently removed. You may also want to abstract this into a state stack object, which manages itself, as well as allowing duplicatation and removal of states (more advanced but a much more powerful abstraction), allowing for rapid state to state transitions. Included in either state management approach, additionally naming states may be of value in your environment, allowing rapid identification, location and re/use states for various testing environments.
| Description: |
| Download, unarchive, drag and drop on Eggplant icon. |
|
 Download |
| Filename: |
RestoreStoreEPProperties.suite.zip |
| Filesize: |
135.41 KB |
| Downloaded: |
894 Time(s) |
|
|
| Back to top |
|
 |
Todd AuberGenie

Joined: 20 Jan 2007 Posts: 265
|
Posted: Fri Oct 12, 2007 12:26 pm Post subject: RE: GetOptions... |
|
|
As a point of ease, there is a function that slipped past my scrutiny screen and it is called GetOptions() which of course returns the Eggplant global options/preferences. Instead of a nifty little loop, you could simply call that and store it.
insert GetOptions() into universal EggplantGlobalPropertys
I hope this did not discourage others from taking the simpler route as Doug Simons pointed out after the above post. The beauty of having so many read this forum is many ways of doing the same thing come to light.
|
|
| Back to top |
|
 |
Todd AuberGenie

Joined: 20 Jan 2007 Posts: 265
|
Posted: Mon Mar 03, 2008 9:21 pm Post subject: RE: naming files in folder/s... |
|
|
Quick and dirty little utility to do extension conversion.
I use this extensively while working with .script files and then moving them to command line production SenseTalk .st files. You will have to connect up with Thoughtful Software (the folks that license SenseTalk for use in Eggplant and other embedded language tools) for information on the STcli availability. Yet, this is just as a handy utility to convert files on your system from possibly '.txt' to other compatible extension file formats like '.text'. You could even remove extensions by playing around with the ext1 and ext2 values, setting the destination extension to empty for instance.
| Code: | universal myLastFolder
-- change these if needed, possibly from .txt <-> .text
set ( ext1, ext2 ) to ( ".st", ".script" )
if myLastFolder is empty or myLastFolder is undefined then
set myLastFolder to "~"
end if
answer directory prompt ext1 & " -> " & ext2 & " : Select folders" in \
folder myLastFolder allow multiple
set dirs to it
if dirs is empty then exit all
if number of items in dirs is 1 then set myLastFolder to dirs
else set myLastFolder to the folder of ( item 1 of dirs )
answer "Rename files to what extension?" with ext1 or ext2 or "Cancel"
if it is Cancel then exit all
if it is ext1 then set origExtension to ext2 else set origExtension to ext1
repeat with each dir in dirs
repeat with each name in the files of dir
if name ends with origExtension then
set dest to name
replace origExtension in dest with it
try
rename file name to dest
put name & " --> " & dest
catch e
put "FAILURE: to rename " & name & " --> " & dest & " - " & e
end try
end if
end repeat
end repeat |
This script will prompt you for the folders which contain files to rename. It will also prompt you for which direction you want to rename, from ext1 to ext2 or the other way around.
I used a exception handler just in case a rename didn't work properly. You can safely remote it with little chance of it failing. Its there to show and sell safe computing with SenseTalk You will also notice a one line if ... then ... else variable setting conditional. Most often you would likely put this on a 5 line
| Code: | if condition then
doSomething wonderful
else
doSomething magical
end if
|
but in this case it made sense to include it all on one line. Looks better, and is appropriately terse, to the point.
And finally. This script will remember the directory you last selected or the parent of multiple folders last selected during the host application run (in this case Eggplant's current run) by using the staying power of a universal variable 'myLastFolder'. The name isn't magical, but the declaration clause 'universal' is special. Once declared, that variable will retain an assigned value between script and suite runs. A very handy offering when I go back and forth in a root folder with many sub folders and projects needing renaming.
I'm sure you will find this powerful and useful too. Explore, there is a lot of goodness in this example of a handy utility to add to your SenseTalk power toolbelt.
| Description: |
| Download and install into your own project, or a shared library project which can then be used with start using, or helpers. You can leverage this by putting this script into your EggplantCommon.suite which is included in your Eggplant.app package conten |
|
 Download |
| Filename: |
RenameFiles.script |
| Filesize: |
1.15 KB |
| Downloaded: |
574 Time(s) |
|
|
| Back to top |
|
 |
Todd AuberGenie

Joined: 20 Jan 2007 Posts: 265
|
Posted: Tue Mar 18, 2008 9:52 am Post subject: RE: ScrollTo ImageName, Direction, waitPeriod |
|
|
Here you will find a simple search image handler allowing you up and down search directions. Most of the time it makes sense to standardized by moving the scroll bar to the top of the view, and proceeding downward. This helps in debugging by simplifying things a bit. However, there are times when it is clearly faster to go to the bottom of the list and start there. Using the homeKey and endKey for TypeText, you can pick either quickly.
| Code: | to scrollTo imageName, direction, waitPeriod
if direction is not in ( "top", "bottom", "left", "right" ) then \
set direction to Bottom
if waitPeriod is not a positive number then set waitPeriod to one quarter second
repeat until ImageFound(waitPeriod, (imageName,(direction & Scroller)))
if direction is Top then
TypeText pageUp
else if direction is Bottom then
TypeText pageDown
end if
end repeat
end scrollTo |
and finally some sample code to get things rolling. You will see in the first call to the handler scrollTo, I have left out the direction and wait period, both default to bottom and .25 seconds. Remember, default top down, and 1/4 second wait time, which is fine for most fast machines. Increase this period to 1/2 or 1 second, or change the script to use the default value set in the Eggplant preferences panel. You are in charge, so take it
| Code: | TypeText homeKey
RefreshScreen -- to avoid false positives
scrollTo 871
TypeText endKey
RefreshScreen
scrollTo 871, top |
In the second call, we go to the end of the web page in question, and force a refresh of the screen to avoid false positives. Then we scroll to the top of the page looking for the image in question. Again, this time using the .25 seconds as default. Slower machine or connection, play with increasing this value.
|
|
| Back to top |
|
 |
Todd AuberGenie

Joined: 20 Jan 2007 Posts: 265
|
Posted: Tue Mar 18, 2008 11:06 am Post subject: RE: Screen Scraping Example |
|
|
Here is a little ditty I wrote to scrape some jokes off a page for validation and reuse. You can expand this script to test against various browsers simply by turning the topLeft, bottomRight, topScroller, bottomScroller into image collections while adding additional SUT images to your suite. Also to note, is the trick to scroll up a bit, scrape, then scroll back down if the bottom of the page has not been reached and scraped.
| Code: | -- URL in browser set to
-- http://4q.cc/index.php?pid=top100&person=chuck
set path to "/tmp/chucknorrisjokes.txt"
delete file path
TypeText homeKey
repeat forever
set topLefts to EveryImageLocation(topLeft)
set bottomRights to EveryImageLocation(bottomRight)
if not aboveAndLeftOf(item 1 of topLefts, item 1 of bottomRights) then \
delete item 1 of bottomRights
repeat with each aBottomRight in bottomRights
DragAndDrop item repeatIndex() of topLefts, aBottomRight
TypeCommand "c"
get remoteClipboard()
if it is not in file path then put it & return after file path
end repeat
if ImageFound(bottomScroller) then exit repeat
else TypeText upArrow, upArrow, upArrow
TypeText pageDown
end repeat
to aboveAndLeftOf pt1, pt2
return ( item 1 of pt1 <= item 1 of pt2 ) and \
( item 2 of pt1 <= item 2 of pt2 )
end aboveAndLeftOf |
The scraped data is stored uniquely into a file, and at the end of the run we would need to either manually validate the existence of 100 expected unique jokes, or do it with script. Writing such a script would need a baseline data source of expected values. This is often the case in proper test conditions, but unique enough of a problem set to be left to the reader.
Although DragAndDrop has been deprecated to the EP 4.x Drag and Drop commands, I still like the concise nature of DragAndDrop. You also may note the use of a inline helper handler called AboveAndLeftOf pt1, pt2... This should be moved to a shared SenseTalk library. Last year I discussed it and related relative positional handlers for points in a posting.
|
|
| Back to top |
|
 |
Todd AuberGenie

Joined: 20 Jan 2007 Posts: 265
|
Posted: Sat Mar 29, 2008 1:20 pm Post subject: Characters to Numbers in a String |
|
|
There are many times when I'm writing interfaces to services like a server for gaming or data from a database where I need to know the contents of a string. However, often working in UTF-8 leaves me with white space at the start or end of a string, or even in the middle that I'm unaware or not easily noticable with my tired eyes.
To strip the start and end white space off, SenseTalk has a handy little trick to do this with the chunk expression words...
| Code: | | get words first to last of someContainer |
which will end up stripping the leading and trailing white spaces. However this does not do any manipulation of white space to the 'inside' of a string. This is great news, leaving tabs and spaces as they were. In the case of my gaming parse scripts, I need then to know what are words two and three to identify the player which a command was issued, and the command itself.
| Code: | | set ( player, command ) to ( second word of it, third word of it ) |
This method of using list assignment is compact and saves an extra line of script and to me personally is a best practice in use where 2, 3 or 4 short named variables are going to be used. However this quickly becomes ackward using long descriptive container names. You will want to move to single line assignments for such cases.
| Code: | set thePlayersNameOrLogin to word 2 of it
[...]
set aCommandIssuedByAPlayer to word 3 of it |
and finally what I was hoping to share with you in the first place, was the ability to find odd unprintable UTF-8 characters in a string that may be causing problems or even signify a special or critical condition in data transmission quality. In my case I have a server that at times pumps out extra characters, linefeeds and returns in the communications coming back from the server. This can cause issues, so I simply delete them all in a line of text so that my log data doesn't have extra vertical line feeds.
| Code: | set ( debug, verbose ) to ( true, true )
repeat until someCondition
read a line from socket gameServer
delete all return from it
delete all linefeed from it
get words first to last of it
if first word of it is 12 then -- 12 means a personal message
set ( player, command ) to ( word 2 of it, word 3 of it )
[...]
if debug then put it
if verbose then put stringToNums(it) -- big list of numbers
end if -- ignore anything but 12 type commands
end repeat |
and here we have the function to output a nice bracketed list of UTF-8 chars to numbers making it fairly easy to identify weird or unexpected characters that may otherwise not be seen in the output.
| Code: | to stringToNums aString
set r to empty
repeat with each char in aString
put "[" & charToNum(it) & "]" after r
end repeat
return r
end stringToNum |
This should help in situations where a string may otherwise look like you may expect it should, yet the string ends with unprintable characters and causing problems in your character by character parsing. I have found this handler handy to have in my SenseTalk function library. I hope you find it useful too.
|
|
| Back to top |
|
 |
Todd AuberGenie

Joined: 20 Jan 2007 Posts: 265
|
Posted: Sat Apr 05, 2008 11:27 pm Post subject: The System Information when reporting... |
|
|
Proper bug reporting helps in quick solutions/fixes/workarounds. This set of handlers and downloadable example set will give you quick and easy access to your system information. This is only one of many ways you could perform this all too repeatative task, which of course computers excel... Mundane.
| Code: |
get SystemGlobalProperites()
put the long date & " - " & the long time
repeat with each key in the keys of it
put format("%15s : %s", key, it.(key))
end repeat
|
and of course the horse that does all the work...
| Code: |
set props to <<hostName>>
repeat with each prop in props
get words 1 to -1 of first item delimited by "(" of prop
set r.(it) to the ( it )
end repeat
return r
|
Property values were taken from the Release Notes, which I highly recommend reading from start to finish.
Expanding on this theme further and shove the data into the appropriate fields of a Mail.app message is left to the astute SenseTalker.
| Description: |
| Download, unarchive, open the document and your mind. Read and learn. |
|
 Download |
| Filename: |
SystemTools.suite.zip |
| Filesize: |
28.6 KB |
| Downloaded: |
700 Time(s) |
|
|
| Back to top |
|
 |
SenseTalkDoug Auberlord

Joined: 27 Jun 2003 Posts: 603 Location: Colorado
|
Posted: Mon Apr 07, 2008 1:18 pm Post subject: |
|
|
Just thought I would add this little suggestion in response to an earlier post. Instead of doing this: | Code: | | set ( player, command ) to ( second word of it, third word of it ) |
note that it's possible to simplify by selecting a list of specific words, like this: | Code: | | set ( player, command ) to words (2,3) of it |
This could be especially nice when you're using a longer variable name than 'it'.
|
|
| Back to top |
|
 |
Todd AuberGenie

Joined: 20 Jan 2007 Posts: 265
|
Posted: Thu Apr 10, 2008 4:41 pm Post subject: RE: Listing Script Names... aka. Script Inventory |
|
|
Doing an inventory of script files can be challenging. For instance, if you want to know all files that say end with ".st" and ".script" from a particular folder down in the folder hierarchy. You can do this using the UNIX 'find' (try "man find") command which is powerful but cryptic at best. There is the Mac OS X Spotlight find feather, a powerful tool worthy knowing, but at times annoying and no very specific enough for my needs. I also know many people turn of Spotlight due to the CPU consumption it takes for dynamic indexing. What I often want to accomplish is a simple directory and subdirectory catalog of all scripts, so this handler was born. You may want to insert this into your EggplantCommon.suite, found inside the Resources directory of your Eggplant.app package.
| Code: | params path, outputPath
if path is not a folder then set path to my folder
else if char -1 of path <> "/" then put "/" after path
if outputPath is not a boolean then set outputPath to false
repeat with each subfolder in the folders in path
HandlerNames path & subfolder, outputPath
end repeat
get ( item 1 delimited by "." of each item of ( the files in path ) where each ends with ".script" or each ends with ".st" ) joined by ", "
if word 1 of it is not empty then
if outputPath then write path & " : " to output
put it
end if
|
This is a recursive handler, which means it can and often does call itself. It does this by isolating the folders of the script's location folder. If however a folder is provided to the handler, a new base folder search other than the default script folder is used. This allows you to drag and drop folder paths into the run window as well to output the paths with an optional second parameter boolean value.
| Code: | HandlerNames
HandlerNames aPath, true -- would output verbosely
|
There are other techniques/ways, however I find this powerful and useful tool quickly allows me to get a handle on handler names. Ninety plus percent of the time I use a simple "HandlerNames", and because I have set up a chain of start using and handlers in the aforementioned suite I'm able to do much much more (explained in a future posting). I also find that if I'm using a handler enough, I push it down into a common suite or library and begin using it as part of my workflow. You too may find this the case, and find this handler very helpful.
One final step to include would be for the astute sensetalk to include and <any> handler that would parse help requests to objects. Say a usage/help object, which helps all objects. This way you could do a "HandlerNames" and then quickly see a handler you want to try, but you don't maybe remember its usage. Then you could just 'send usage to objName' or just type 'help object' and output of the proper usage would be presented. Very powerful, very simple to implement, you just need to spend a bit of time understanding the message passing system of SenseTalk.
Do some homework by digging into the SenseTalk Reference manual, in particular Objects and Messages. You'll be amazed at what you come up with for a custom solution to your needs.
NOTE: Please do not confused proper and thoughtful design and workflow analysis to gratifying haste makes waste approach. Understand your environment needs, your business needs, nobody will question you if you have thought about it even if it is tailored to your personal needs. This adds a lot of value to your position and adds to your knowledge of various approaches. Knowing why one is better than another and how they work in your world is key to being a continued asset to your company and its stake holders.
Also note that almost every single smalltalk system on the planet uses ".st" suffix, so don't be surprised if you come with a lot of non SenseTalk scripts when doing a system side "HandlerNames /Users/<aUserLogin>" or other high level searches.
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|
|