rb-scrpt 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +497 -0
  3. data/README.md +8 -0
  4. data/Rakefile +32 -0
  5. data/doc/aem-manual/01_introduction.html +60 -0
  6. data/doc/aem-manual/02_apioverview.html +107 -0
  7. data/doc/aem-manual/03_packingandunpackingdata.html +135 -0
  8. data/doc/aem-manual/04_references.html +409 -0
  9. data/doc/aem-manual/05_targetingapplications.html +164 -0
  10. data/doc/aem-manual/06_buildingandsendingevents.html +229 -0
  11. data/doc/aem-manual/07_findapp.html +63 -0
  12. data/doc/aem-manual/08_examples.html +94 -0
  13. data/doc/aem-manual/aemreferenceinheritance.gif +0 -0
  14. data/doc/aem-manual/index.html +56 -0
  15. data/doc/appscript-manual/01_introduction.html +94 -0
  16. data/doc/appscript-manual/02_aboutappscripting.html +247 -0
  17. data/doc/appscript-manual/03_quicktutorial.html +167 -0
  18. data/doc/appscript-manual/04_gettinghelp.html +188 -0
  19. data/doc/appscript-manual/05_keywordconversion.html +106 -0
  20. data/doc/appscript-manual/06_classesandenums.html +192 -0
  21. data/doc/appscript-manual/07_applicationobjects.html +211 -0
  22. data/doc/appscript-manual/08_realvsgenericreferences.html +96 -0
  23. data/doc/appscript-manual/09_referenceforms.html +241 -0
  24. data/doc/appscript-manual/10_referenceexamples.html +154 -0
  25. data/doc/appscript-manual/11_applicationcommands.html +245 -0
  26. data/doc/appscript-manual/12_commandexamples.html +138 -0
  27. data/doc/appscript-manual/13_performanceissues.html +142 -0
  28. data/doc/appscript-manual/14_notes.html +80 -0
  29. data/doc/appscript-manual/application_architecture.gif +0 -0
  30. data/doc/appscript-manual/application_architecture2.gif +0 -0
  31. data/doc/appscript-manual/finder_to_textedit_event.gif +0 -0
  32. data/doc/appscript-manual/index.html +62 -0
  33. data/doc/appscript-manual/relationships_example.gif +0 -0
  34. data/doc/appscript-manual/ruby_to_itunes_event.gif +0 -0
  35. data/doc/full.css +106 -0
  36. data/doc/index.html +45 -0
  37. data/doc/mactypes-manual/01_introduction.html +54 -0
  38. data/doc/mactypes-manual/02_aliasclass.html +124 -0
  39. data/doc/mactypes-manual/03_fileurlclass.html +126 -0
  40. data/doc/mactypes-manual/04_unitsclass.html +100 -0
  41. data/doc/mactypes-manual/index.html +53 -0
  42. data/doc/osax-manual/01_introduction.html +67 -0
  43. data/doc/osax-manual/02_interface.html +147 -0
  44. data/doc/osax-manual/03_examples.html +73 -0
  45. data/doc/osax-manual/04_notes.html +61 -0
  46. data/doc/osax-manual/index.html +53 -0
  47. data/doc/rb-appscript-logo.png +0 -0
  48. data/extconf.rb +63 -0
  49. data/rb-scrpt.gemspec +16 -0
  50. data/sample/AB_export_vcard.rb +31 -0
  51. data/sample/AB_list_people_with_emails.rb +13 -0
  52. data/sample/Add_iCal_event.rb +21 -0
  53. data/sample/Create_daily_iCal_todos.rb +75 -0
  54. data/sample/Export_Address_Book_phone_numbers.rb +59 -0
  55. data/sample/Hello_world.rb +21 -0
  56. data/sample/List_iTunes_playlist_names.rb +11 -0
  57. data/sample/Make_Mail_message.rb +33 -0
  58. data/sample/Open_file_in_TextEdit.rb +13 -0
  59. data/sample/Organize_Mail_messages.rb +61 -0
  60. data/sample/Print_folder_tree.rb +16 -0
  61. data/sample/Select_all_HTML_files.rb +14 -0
  62. data/sample/Set_iChat_status.rb +24 -0
  63. data/sample/Simple_Finder_GUI_Scripting.rb +18 -0
  64. data/sample/Stagger_Finder_windows.rb +25 -0
  65. data/sample/TextEdit_demo.rb +130 -0
  66. data/sample/iTunes_top40_to_html.rb +69 -0
  67. data/src/SendThreadSafe.c +380 -0
  68. data/src/SendThreadSafe.h +139 -0
  69. data/src/lib/_aem/aemreference.rb +1021 -0
  70. data/src/lib/_aem/codecs.rb +661 -0
  71. data/src/lib/_aem/connect.rb +205 -0
  72. data/src/lib/_aem/encodingsupport.rb +74 -0
  73. data/src/lib/_aem/findapp.rb +85 -0
  74. data/src/lib/_aem/mactypes.rb +250 -0
  75. data/src/lib/_aem/send.rb +279 -0
  76. data/src/lib/_aem/typewrappers.rb +59 -0
  77. data/src/lib/_appscript/defaultterminology.rb +277 -0
  78. data/src/lib/_appscript/referencerenderer.rb +242 -0
  79. data/src/lib/_appscript/reservedkeywords.rb +116 -0
  80. data/src/lib/_appscript/safeobject.rb +250 -0
  81. data/src/lib/_appscript/terminology.rb +470 -0
  82. data/src/lib/aem.rb +253 -0
  83. data/src/lib/kae.rb +1489 -0
  84. data/src/lib/osax.rb +659 -0
  85. data/src/lib/rb-scrpt.rb +1073 -0
  86. data/src/lib/version.rb +3 -0
  87. data/src/rbae.c +979 -0
  88. data/test/README +3 -0
  89. data/test/test_aemreference.rb +115 -0
  90. data/test/test_appscriptcommands.rb +149 -0
  91. data/test/test_appscriptreference.rb +103 -0
  92. data/test/test_codecs.rb +181 -0
  93. data/test/test_findapp.rb +23 -0
  94. data/test/test_mactypes.rb +77 -0
  95. data/test/test_osax.rb +52 -0
  96. metadata +146 -0
data/test/README ADDED
@@ -0,0 +1,3 @@
1
+ Some of the code in these tests may not yet be 100% portable (hardcoded paths, etc) so may currently fail for some users, although they have passed for Ruby 1.8.x on OS X 10.3.9, OS X 10.4.x (PPC & i386) and OS X 10.5.1 (i386).
2
+
3
+ Note that some mactypes unit tests may fail as Alias and FileURL comparisons are rather dumb and don't normalise path strings before comparing/hashing. Future releases may try to remedy this.
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ require 'minitest/autorun'
4
+ require "_aem/aemreference"
5
+ require "_aem/typewrappers"
6
+ require "_aem/codecs"
7
+
8
+
9
+ class TC_AEMReferences < Minitest::Test
10
+
11
+ def test_reference_forms
12
+ [
13
+ [AEMReference::App.property('ctxt'), 'AEM.app.property("ctxt")', nil],
14
+
15
+ [AEMReference::App.elements('docu'), 'AEM.app.elements("docu")', nil],
16
+
17
+ [AEMReference::App.elements('docu').by_index(1),
18
+ 'AEM.app.elements("docu").by_index(1)', nil],
19
+ [AEMReference::App.elements('docu').by_name('foo'),
20
+ 'AEM.app.elements("docu").by_name("foo")', nil],
21
+ [AEMReference::App.elements('docu').by_id(300),
22
+ 'AEM.app.elements("docu").by_id(300)', nil],
23
+
24
+ [AEMReference::App.elements('docu').next('docu'),
25
+ 'AEM.app.elements("docu").next("docu")', nil],
26
+ [AEMReference::App.elements('docu').previous('docu'),
27
+ 'AEM.app.elements("docu").previous("docu")', nil],
28
+
29
+ [AEMReference::App.elements('docu').first, 'AEM.app.elements("docu").first', nil],
30
+ [AEMReference::App.elements('docu').middle, 'AEM.app.elements("docu").middle', nil],
31
+ [AEMReference::App.elements('docu').last, 'AEM.app.elements("docu").last', nil],
32
+ [AEMReference::App.elements('docu').any, 'AEM.app.elements("docu").any', nil],
33
+
34
+ [AEMReference::Con.elements("docu").by_index(3), 'AEM.con.elements("docu").by_index(3)', nil],
35
+
36
+ [AEMReference::App.elements('docu').by_range(
37
+ AEMReference::Con.elements('docu').by_index(3),
38
+ AEMReference::Con.elements('docu').by_name('foo')),
39
+ 'AEM.app.elements("docu").by_range(' +
40
+ 'AEM.con.elements("docu").by_index(3), ' +
41
+ 'AEM.con.elements("docu").by_name("foo"))', nil],
42
+
43
+ [AEMReference::App.elements('docu').by_range(1, 'foo'),
44
+ 'AEM.app.elements("docu").by_range(1, "foo")',
45
+ AEMReference::App.elements("docu").by_range(
46
+ AEMReference::Con.elements("docu").by_index(1),
47
+ AEMReference::Con.elements("docu").by_name("foo"))],
48
+
49
+ [AEMReference::Its.property('name').eq('foo').and(AEMReference::Its.elements('cwor').eq([])),
50
+ 'AEM.its.property("name").eq("foo").and(AEM.its.elements("cwor").eq([]))', nil],
51
+
52
+ [AEMReference::Its.elements('cwor').ne([]),
53
+ 'AEM.its.elements("cwor").ne([])',
54
+ AEMReference::Its.elements("cwor").eq([]).not], # i.e. there isn't a KAENotEqual operator, so not-equal tests are actually packed as an equal test followed by not test
55
+
56
+ [AEMReference::Its.elements('cwor').eq(nil), 'AEM.its.elements("cwor").eq(nil)', nil],
57
+ [AEMReference::Its.elements('cwor').property('leng').gt(0),
58
+ 'AEM.its.elements("cwor").property("leng").gt(0)', nil],
59
+ [AEMReference::Its.elements('cwor').le(''), 'AEM.its.elements("cwor").le("")', nil],
60
+ [AEMReference::Its.elements('cwor').begins_with('foo').not,
61
+ 'AEM.its.elements("cwor").begins_with("foo").not', nil],
62
+
63
+
64
+ [AEMReference::Its.elements('cwor').contains('foo'), 'AEM.its.elements("cwor").contains("foo")', nil],
65
+ [AEMReference::Its.elements('cwor').is_in('foo'), 'AEM.its.elements("cwor").is_in("foo")', nil],
66
+
67
+ [AEMReference::App.elements('docu').by_filter(AEMReference::Its.property('size').ge(42)),
68
+ 'AEM.app.elements("docu").by_filter(AEM.its.property("size").ge(42))', nil],
69
+
70
+ [AEMReference::App.elements('docu').by_index(1).property('ctxt') \
71
+ .elements('cpar').elements('cha ').by_range(
72
+ AEMReference::Con.elements('cha ').by_index(3),
73
+ AEMReference::Con.elements('cha ').by_index(55)
74
+ ).next('cha ').after,
75
+ 'AEM.app.elements("docu").by_index(1).property("ctxt").elements("cpar").elements("cha ")' +
76
+ '.by_range(AEM.con.elements("cha ").by_index(3), AEM.con.elements("cha ").by_index(55))' +
77
+ '.next("cha ").after', nil],
78
+
79
+ [AEMReference::Its.property('pnam').ne('foo').and(AEMReference::Its.elements('cfol').eq([])).not,
80
+ 'AEM.its.property("pnam").ne("foo").and(AEM.its.elements("cfol").eq([])).not',
81
+ AEMReference::Its.property('pnam').eq('foo').not.and(AEMReference::Its.elements('cfol').eq([])).not],
82
+
83
+ [AEMReference::App.elements('docu').beginning, 'AEM.app.elements("docu").beginning', nil],
84
+ [AEMReference::App.elements('docu').end, 'AEM.app.elements("docu").end', nil],
85
+ [AEMReference::App.elements('docu').by_index(3).before, 'AEM.app.elements("docu").by_index(3).before', nil],
86
+ [AEMReference::App.elements('docu').by_name('foo').after, 'AEM.app.elements("docu").by_name("foo").after', nil],
87
+
88
+ ].each do |val, res, unpacked_version|
89
+ begin
90
+ assert_equal(res, val.to_s)
91
+ d = DefaultCodecs.pack(val)
92
+ val = unpacked_version ? unpacked_version : val
93
+ val2 = DefaultCodecs.unpack(d)
94
+ assert_equal(val, val2)
95
+ val2 = DefaultCodecs.unpack(d)
96
+ assert_predicate val, :eql?, val2
97
+ val2 = DefaultCodecs.unpack(d)
98
+ assert_equal(val2, val)
99
+ val2 = DefaultCodecs.unpack(d)
100
+ assert_predicate val2, :eql?, val
101
+ rescue
102
+ puts 'EXPECTED: ' + res
103
+ raise
104
+ end
105
+ end
106
+ refute_equal(AEMReference::App.property('ctxt').property('ctxt'), AEMReference::Con.property('ctxt').property('ctxt'))
107
+ refute_equal(AEMReference::App.property('foob').property('ctxt'), AEMReference::App.property('ctxt').property('ctxt'))
108
+ refute_equal(AEMReference::App.elements('ctxt').property('ctxt'), AEMReference::App.property('ctxt').property('ctxt'))
109
+ refute_equal(AEMReference::App.elements('ctxt').property('ctxt'), 333)
110
+ refute_equal(333, AEMReference::App.property('ctxt').property('ctxt'))
111
+ # # by-filter references do basic type checking to ensure an its-based reference is given
112
+ assert_raises(TypeError) { AEMReference::App.elements('docu').by_filter(1) }
113
+
114
+ end
115
+ end
@@ -0,0 +1,149 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ require 'minitest/autorun'
4
+ require 'rb-scpt'
5
+
6
+ # rb-appscript 0.5.0+ should no longer require the following kludge:
7
+ #class AS_SafeObject
8
+ # def self.hide(name)
9
+ # end
10
+ #end
11
+
12
+ class TC_AppscriptNewApp < Minitest::Test
13
+
14
+ def test_by_name
15
+ [
16
+ '/Applications/TextEdit.app',
17
+ 'Finder.app',
18
+ 'System Events'
19
+ ].each do |name|
20
+ a = Appscript.app(name)
21
+ refute_nil(a)
22
+ assert_instance_of(Appscript::Application, a)
23
+ assert_instance_of(Appscript::Reference, a.name)
24
+ end
25
+ assert_equal('app("/Applications/TextEdit.app")', Appscript.app('TextEdit').to_s)
26
+ assert_equal('app("/Applications/TextEdit.app")', Appscript.app.by_name('TextEdit').to_s)
27
+
28
+ assert_raises(Appscript::ApplicationNotFoundError) { Appscript.app('/non-existent/app') }
29
+ assert_raises(Appscript::ApplicationNotFoundError) { Appscript.app('non-existent.app') }
30
+ end
31
+
32
+ def test_by_id
33
+ [
34
+ 'com.apple.textedit',
35
+ 'com.apple.finder',
36
+ ].each do |name|
37
+ a = Appscript.app.by_id(name)
38
+ refute_nil(a)
39
+ assert_instance_of(Appscript::Application, a)
40
+ assert_instance_of(Appscript::Reference, a.name)
41
+ end
42
+ assert_equal('app("/Applications/TextEdit.app")', Appscript.app.by_id('com.apple.textedit').to_s)
43
+
44
+ assert_raises(Appscript::ApplicationNotFoundError) { Appscript.app.by_id('non.existent.app') }
45
+ end
46
+
47
+ def test_by_creator
48
+ a = Appscript.app.by_creator('ttxt')
49
+ assert_instance_of(Appscript::Reference, a.name)
50
+ assert_equal('app("/Applications/TextEdit.app")', a.to_s)
51
+ assert_raises(Appscript::ApplicationNotFoundError) { Appscript.app.by_id('!@$o') }
52
+ end
53
+
54
+ def test_by_pid
55
+ pid = `top -l1 | grep Finder | awk '{ print $1 }'`.to_i # note: this line will return a bad result if more than one user is logged in
56
+ a = Appscript.app.by_pid(pid)
57
+ assert_instance_of(Appscript::Reference, a.name)
58
+ assert_equal("app.by_pid(#{pid})", a.to_s)
59
+ assert_equal('Finder', a.name.get)
60
+ end
61
+
62
+ def test_by_aem_app
63
+ a = Appscript.app.by_aem_app(AEM::Application.by_path('/Applications/TextEdit.app'))
64
+ assert_instance_of(Appscript::Reference, a.name)
65
+ assert_equal('app.by_aem_app(AEM::Application.by_path("/Applications/TextEdit.app"))', a.to_s)
66
+ end
67
+ end
68
+
69
+
70
+ class TC_AppscriptCommands < Minitest::Test
71
+
72
+ def setup
73
+ @te = Appscript.app('TextEdit')
74
+ @f = Appscript.app('Finder')
75
+ end
76
+
77
+ def test_commands_1
78
+ assert_equal('TextEdit', @te.name.get)
79
+ d = @te.make(:new=>:document, :with_properties=>{:text=>'test test_commands'})
80
+ assert_instance_of(Appscript::Reference, d)
81
+ d.text.end.make(:new=>:word, :with_data=>' test2')
82
+ assert_equal('test test_commands test2', d.text.get)
83
+ assert_instance_of(String,
84
+ d.text.get(:ignore=>[:diacriticals, :punctuation, :whitespace, :expansion], :timeout=>10))
85
+ assert_nil(d.get(:wait_reply=>false))
86
+
87
+
88
+ # test Ruby 1.9+ String Encoding support
89
+ version, sub_version = RUBY_VERSION.split('.').collect {|n| n.to_i} [0, 2]
90
+ if version >= 1 and sub_version >= 9
91
+
92
+ print "(check Encoding support)"
93
+ s = "\302\251 M. Lef\303\250vre"
94
+ s.force_encoding('utf-8')
95
+ d.text.set(s)
96
+ assert_equal(s, d.text.get)
97
+
98
+ @te.AS_app_data.use_ascii_8bit
99
+ end
100
+
101
+ d.text.set("\302\251 M. Lef\303\250vre")
102
+ assert_equal("\302\251 M. Lef\303\250vre", d.text.get)
103
+
104
+ d.close(:saving=>:no)
105
+ end
106
+
107
+ def test_commands_2
108
+ d = @te.make(:new=>:document, :at=>@te.documents.end)
109
+
110
+ @te.set(d.text, :to=> 'test1')
111
+ assert_equal('test1', d.text.get)
112
+
113
+ @te.set(d.text, :to=> 'test2')
114
+ @te.make(:new=>:word, :at=>Appscript.app.documents[1].paragraphs.end, :with_data=>' test3')
115
+ assert_equal('test2 test3', d.text.get)
116
+
117
+ d.close(:saving=>:no)
118
+
119
+ assert_raises(Appscript::CommandError) { @te.documents[10000].get }
120
+
121
+ assert_kind_of(Integer, @te.documents.count)
122
+ assert_equal(@te.documents.count, @te.count(:each=>:document))
123
+ end
124
+
125
+ def test_commands_3
126
+ assert_equal('Finder', @f.name.get)
127
+ val = @f.home.folders['Desktop'].get(:result_type=>:alias)
128
+ assert_instance_of(MacTypes::Alias, val)
129
+ assert_equal(val, @f.desktop.get(:result_type=>:alias))
130
+ assert_instance_of(Array, @f.disks.get)
131
+
132
+ r = @f.home.get
133
+ f = r.get(:result_type=>:file_ref)
134
+ assert_equal(r, @f.items[f].get)
135
+
136
+ assert_equal(@f.home.items.get, @f.home.items.get)
137
+ refute_equal(@f.disks['non-existent'], @f.disks[1].get)
138
+ end
139
+
140
+ def test_command_error
141
+ begin
142
+ @f.items[10000].get
143
+ rescue Appscript::CommandError => e
144
+ assert_equal(-1728, e.to_i)
145
+ assert_equal("CommandError\n\t\tOSERROR: -1728\n\t\tMESSAGE: Can't get reference.\n\t\tOFFENDING OBJECT: app(\"/System/Library/CoreServices/Finder.app\").items[10000]\n\t\tCOMMAND: app(\"/System/Library/CoreServices/Finder.app\").items[10000].get()\n", e.to_s)
146
+ assert_instance_of(AEM::EventError, e.real_error)
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ require 'minitest/autorun'
4
+ require "rb-scpt"
5
+
6
+ class TC_AppscriptReferences < Minitest::Test
7
+
8
+ def setup
9
+ @te = Appscript.app('TextEdit')
10
+ @s = @te.to_s
11
+ end
12
+
13
+ def test_reference_forms
14
+ [
15
+
16
+ [@te.documents[
17
+ Appscript.con.documents[3],
18
+ Appscript.con.documents['foo']],
19
+ @s+'.documents[' +
20
+ 'con.documents[3], ' +
21
+ 'con.documents["foo"]]', nil],
22
+
23
+
24
+
25
+ [@te.text, @s+'.text', nil],
26
+
27
+ [@te.documents, @s+'.documents', nil],
28
+
29
+ [@te.documents[1],
30
+ @s+'.documents[1]', nil],
31
+ [@te.documents['foo'],
32
+ @s+'.documents["foo"]', nil],
33
+ [@te.documents.ID(300),
34
+ @s+'.documents.ID(300)', nil],
35
+
36
+ [@te.documents.next(:document),
37
+ @s+'.documents.next(:document)', nil],
38
+ [@te.documents.previous(:document),
39
+ @s+'.documents.previous(:document)', nil],
40
+
41
+ [@te.documents.first, @s+'.documents.first', nil],
42
+ [@te.documents.middle, @s+'.documents.middle', nil],
43
+ [@te.documents.last, @s+'.documents.last', nil],
44
+ [@te.documents.any, @s+'.documents.any', nil],
45
+
46
+ [Appscript.con.documents[3], 'con.documents[3]', nil],
47
+
48
+
49
+ [Appscript.its.name.eq('foo').and(Appscript.its.words.eq([])),
50
+ 'its.name.eq("foo").and(its.words.eq([]))', nil],
51
+
52
+ [Appscript.its.words.ne([]),
53
+ 'its.words.ne([])',
54
+ Appscript.its.words.eq([]).not], # i.e. there isn't a KAENotEqual operator, so not-equal tests are actually packed as an equal test followed by not test
55
+
56
+ [Appscript.its.words.eq(nil), 'its.words.eq(nil)', nil],
57
+ [Appscript.its.words.size.gt(0),
58
+ 'its.words.size.gt(0)', nil],
59
+ [Appscript.its.words.le(''), 'its.words.le("")', nil],
60
+ [Appscript.its.words.begins_with('foo').not,
61
+ 'its.words.begins_with("foo").not', nil],
62
+
63
+
64
+ [Appscript.its.words.contains('foo'), 'its.words.contains("foo")', nil],
65
+ [Appscript.its.words.is_in('foo'), 'its.words.is_in("foo")', nil],
66
+
67
+ [@te.documents[Appscript.its.size.ge(42)],
68
+ @s+'.documents[its.size.ge(42)]', nil],
69
+
70
+ [@te.documents[1, 'foo'],
71
+ @s+'.documents[1, "foo"]',
72
+ @te.documents[Appscript.con.documents[1], Appscript.con.documents["foo"]]],
73
+
74
+ [@te.documents[1].text \
75
+ .paragraphs.characters[
76
+ Appscript.con.characters[3],
77
+ Appscript.con.characters[55]
78
+ ].next(:character).after,
79
+ @s+'.documents[1].text.paragraphs.characters' +
80
+ '[con.characters[3], con.characters[55]]' +
81
+ '.next(:character).after', nil],
82
+
83
+ [Appscript.its.name.ne('foo').and(Appscript.its.words.eq([])).not,
84
+ 'its.name.ne("foo").and(its.words.eq([])).not',
85
+ Appscript.its.name.eq('foo').not.and(Appscript.its.words.eq([])).not],
86
+
87
+ [@te.documents.beginning, @s+'.documents.beginning', nil],
88
+ [@te.documents.end, @s+'.documents.end', nil],
89
+ [@te.documents[3].before, @s+'.documents[3].before', nil],
90
+ [@te.documents['foo'].after, @s+'.documents["foo"].after', nil],
91
+
92
+ ].each do |val, res, unpacked_version|
93
+ assert_equal(res, val.to_s)
94
+ d = @te.AS_app_data.pack(val)
95
+ val = unpacked_version ? unpacked_version : val
96
+ val2 = @te.AS_app_data.unpack(d)
97
+ if val.class == @te.AS_app_data.unpack(d).class # note: Appscript::Reference and Appscript::GenericReference currently aren't comparable with each other, so the next test would always fail for those
98
+ assert_equal(val, val2)
99
+ assert_predicate val, :eql?, val2
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ require 'minitest/autorun'
4
+ require 'aem'
5
+ require 'kae'
6
+ require 'ae'
7
+
8
+ def num(s)
9
+ if [1].pack('s') == "\001\000" # host system is i386
10
+ s.reverse
11
+ else
12
+ s
13
+ end
14
+ end
15
+
16
+ def ut16(s)
17
+ if [1].pack('s') == "\001\000" # host system is i386
18
+ i = 0
19
+ s2 = ''
20
+ (s.length / 2).times do
21
+ s2 += s[i, 2].reverse
22
+ i+=2
23
+ end
24
+ s2
25
+ else
26
+ s
27
+ end
28
+ end
29
+
30
+ class TC_Codecs < Minitest::Test
31
+
32
+ def setup
33
+ @c = AEM::Codecs.new
34
+ end
35
+
36
+ def test_nil
37
+ d = @c.pack(nil)
38
+ assert_equal(KAE::TypeNull, d.type)
39
+ assert_equal('', d.data)
40
+ assert_nil(@c.unpack(d))
41
+ end
42
+
43
+ def test_bool
44
+ [
45
+ [true, KAE::TypeTrue],
46
+ [false, KAE::TypeFalse]
47
+ ].each do |val, type|
48
+ d = @c.pack(val)
49
+ assert_equal(type, d.type)
50
+ assert_equal('', d.data)
51
+ assert_equal(val, @c.unpack(d))
52
+ end
53
+ assert_equal(true, @c.unpack(AE::AEDesc.new(KAE::TypeBoolean, "\xfe")))
54
+ assert_equal(true, @c.unpack(AE::AEDesc.new(KAE::TypeTrue, '')))
55
+ assert_equal(false, @c.unpack(AE::AEDesc.new(KAE::TypeFalse, '')))
56
+ end
57
+
58
+ def test_num
59
+ [ # (mostly testing at threshold points where Codecs switches types when packing integers)
60
+ [0, "\x00\x00\x00\x00", KAE::TypeInteger],
61
+ [2, "\x00\x00\x00\x02", KAE::TypeInteger],
62
+ [-9, "\xff\xff\xff\xf7", KAE::TypeInteger],
63
+ [2**31-1, "\x7f\xff\xff\xff", KAE::TypeInteger],
64
+ [-2**31, "\x80\x00\x00\x00", KAE::TypeInteger],
65
+ [2**31, "\x00\x00\x00\x00\x80\x00\x00\x00", KAE::TypeSInt64],
66
+ [2**32-1, "\x00\x00\x00\x00\xff\xff\xff\xff", KAE::TypeSInt64],
67
+ [2**32, "\x00\x00\x00\x01\x00\x00\x00\x00", KAE::TypeSInt64],
68
+ [-2**32, "\xff\xff\xff\xff\x00\x00\x00\x00", KAE::TypeSInt64],
69
+ [2**63-1, "\x7f\xff\xff\xff\xff\xff\xff\xff", KAE::TypeSInt64],
70
+ [-2**63, "\x80\x00\x00\x00\x00\x00\x00\x00", KAE::TypeSInt64],
71
+ [-2**63+1, "\x80\x00\x00\x00\x00\x00\x00\x01", KAE::TypeSInt64],
72
+ [2**63, "C\xe0\x00\x00\x00\x00\x00\x00", KAE::TypeFloat],
73
+ [-2**63-1, "\xc3\xe0\x00\x00\x00\x00\x00\x00", KAE::TypeFloat],
74
+ [0.1, "?\xb9\x99\x99\x99\x99\x99\x9a", KAE::TypeFloat],
75
+ [-0.9e-9, "\xbe\x0e\xec{\xd5\x12\xb5r", KAE::TypeFloat],
76
+ [2**300, "R\xb0\x00\x00\x00\x00\x00\x00", KAE::TypeFloat],
77
+ ].each do |val, data, type|
78
+ data = num(data)
79
+ d = @c.pack(val)
80
+ assert_equal(type, d.type)
81
+ assert_equal(data, d.data)
82
+ assert_equal(val, @c.unpack(d))
83
+ end
84
+ end
85
+
86
+ def test_str
87
+ s = "\xc6\x92\xe2\x88\x82\xc2\xae\xd4\xb7\xd5\x96\xd4\xb9\xe0\xa8\x89\xe3\x82\xa2\xe3\x84\xbb"
88
+ # test Ruby 1.9+ String Encoding support
89
+ version, sub_version = RUBY_VERSION.split('.').collect {|n| n.to_i} [0, 2]
90
+ if version >= 1 and sub_version >= 9
91
+ s.force_encoding('utf-8')
92
+ end
93
+
94
+ [
95
+ # note: aem has to pack UTF8 data as typeUnicodeText (UTF16) as stupid apps expect that type and will error on typeUTF8Text instead of just asking AEM to coerce it to the desired type in advance.
96
+ # note: UTF16 BOM must be omitted when packing UTF16 data into typeUnicodeText AEDescs, as a BOM will upset stupid apps like iTunes 7 that don't recognise it as a BOM and treat it as character data instead
97
+ ['', ''],
98
+ ['hello', "\000h\000e\000l\000l\000o"],
99
+ [s, "\x01\x92\"\x02\x00\xae\x057\x05V\x059\n\t0\xa21;"],
100
+ ].each do |val, data|
101
+ data = ut16(data)
102
+ d = @c.pack(val)
103
+ assert_equal(KAE::TypeUnicodeText, d.type)
104
+ assert_equal(data, d.data)
105
+ assert_equal(val, @c.unpack(d))
106
+ end
107
+ assert_raises(TypeError) { @c.pack("\x88") } # non-valid UTF8 strings should raise error when coercing from typeUTF8Text to typeUnicodeText
108
+ end
109
+
110
+ def test_date
111
+ # note: not testing on ST-DST boundaries; this is known to have out-by-an-hour problems due to LongDateTime type being crap
112
+ [
113
+ [Time.local(2005, 12, 11, 15, 40, 43), "\x00\x00\x00\x00\xbf\xc1\xf8\xfb"],
114
+ [Time.local(2005, 5, 1, 6, 51, 7), "\x00\x00\x00\x00\xbe\x9a\x2c\xdb"],
115
+ ].each do |t, data|
116
+ data = num(data)
117
+ d = @c.pack(t)
118
+ assert_equal(KAE::TypeLongDateTime, d.type)
119
+ assert_equal(data, d.data)
120
+ assert_equal(t, @c.unpack(AE::AEDesc.new(KAE::TypeLongDateTime, data)))
121
+ end
122
+ end
123
+
124
+ def test_file
125
+ path = '/Applications/TextEdit.app'
126
+ d = @c.pack(MacTypes::Alias.path(path))
127
+ assert_equal(path, @c.unpack(d).to_s)
128
+
129
+ path = '/Applications/TextEdit.app'
130
+ d = @c.pack(MacTypes::FileURL.path(path))
131
+ assert_equal(path, @c.unpack(d).to_s)
132
+ end
133
+
134
+ def test_typewrappers
135
+ [
136
+ AEM::AEType.new("docu"),
137
+ AEM::AEEnum.new('yes '),
138
+ AEM::AEProp.new('pnam'),
139
+ AEM::AEKey.new('ABCD'),
140
+ ].each do |val|
141
+ d = @c.pack(val)
142
+ val2 = @c.unpack(d)
143
+ assert_equal(val, val2)
144
+ assert_predicate val, :eql?, val2
145
+ val2 = @c.unpack(d)
146
+ assert_equal(val2, val)
147
+ assert_predicate val2, :eql?, val
148
+ end
149
+ assert_raises(ArgumentError) { AEM::AEType.new(3) }
150
+ assert_raises(ArgumentError) { AEM::AEType.new("docum") }
151
+ end
152
+
153
+ def test_list
154
+ end
155
+
156
+ def test_hash
157
+ val = {'foo' => 1, AEM::AEType.new('foob') => 2, AEM::AEProp.new('barr') => 3}
158
+ expected_val = {'foo' => 1, AEM::AEType.new('foob') => 2, AEM::AEType.new('barr') => 3} # note that four-char-code keys are always unpacked as AEType
159
+ d = @c.pack(val)
160
+ assert_equal(expected_val, @c.unpack(d))
161
+ end
162
+
163
+ def test_units
164
+ val = MacTypes::Units.new(3.3, :inches)
165
+ assert_equal(:inches, val.type)
166
+ assert_equal(3.3, val.value)
167
+ d = @c.pack(val)
168
+ assert_equal('inch', d.type)
169
+ assert_equal(3.3, @c.unpack(d.coerce(KAE::TypeFloat)))
170
+ val2 = @c.unpack(d)
171
+ assert_equal(val, val2)
172
+ assert_equal(:inches, val2.type)
173
+ assert_equal(3.3, val2.value)
174
+ end
175
+
176
+ def test_app
177
+ val = AEM::Application.by_path(FindApp.by_name('TextEdit'))
178
+ d = @c.pack(val)
179
+ assert_equal(KAE::TypeProcessSerialNumber, d.type)
180
+ end
181
+ end
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ require 'minitest/autorun'
4
+ require "_aem/findapp"
5
+
6
+
7
+ class TC_FindApp < Minitest::Test
8
+
9
+ def test_find
10
+ [
11
+ ['/Applications/iCal.app', '/Applications/iCal.app'],
12
+ ['ical.app', '/Applications/iCal.app'],
13
+ ['ICAL', '/Applications/iCal.app'],
14
+ ].each do |val, res|
15
+ assert_equal(res, FindApp.by_name(val))
16
+ end
17
+ assert_equal('/Applications/TextEdit.app', FindApp.by_creator('ttxt'))
18
+ assert_equal('/System/Library/CoreServices/Finder.app', FindApp.by_id('com.apple.finder'))
19
+ assert_raises(FindApp::ApplicationNotFoundError) { FindApp.by_name('NON-EXISTENT-APP') }
20
+
21
+ # assert_equal("/Users/has/\306\222\303\270u\314\210.app", FindApp.by_name("\306\222\303\270u\314\210.app")) # utf8 paths work ok
22
+ end
23
+ end
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ require 'minitest/autorun'
4
+ require "_aem/mactypes"
5
+
6
+
7
+ class TC_MacTypes < Minitest::Test
8
+
9
+ def setup
10
+ @path1 = `mktemp -t codecs-test`.chomp
11
+ dir, fname = File.split(@path1)
12
+ @path2 = File.join(dir, 'moved-' + fname)
13
+ # puts "path: #{@path1}" # e.g. /tmp/codecs-test.HWr1EnE3
14
+ end
15
+
16
+ def normalize(path)
17
+ return path.gsub(/\/+/, '/') # quick-n-dirty
18
+ end
19
+
20
+ def test_alias
21
+ # make alias
22
+ f = MacTypes::Alias.path(@path1)
23
+
24
+
25
+ assert_equal(MacTypes::Alias.path(@path1), f)
26
+
27
+ # get path
28
+ # note that initial /tmp/codecs-test... path will automatically change to /private/tmp/codecs-test...
29
+ p1 = normalize('/private'+@path1)
30
+ p2 = normalize('/private'+@path2)
31
+
32
+ assert_equal(p1, normalize(f.path))
33
+
34
+ #puts "alias path 1: #{f}" # e.g. /private/tmp/codecs-test.HWr1EnE3
35
+ assert_equal(p1, f.to_s)
36
+
37
+ # get desc
38
+ #puts f.desc.type, f.desc.data # alis, [binary data]
39
+ assert_equal('alis', f.desc.type)
40
+
41
+
42
+ # check alias keeps track of moved file
43
+ `mv #{@path1} #{@path2}`
44
+ # puts "alias path 2: #{f}" # /private/tmp/moved-codecs-test.HWr1EnE3
45
+ assert_equal(p2, f.to_s)
46
+
47
+ assert_equal(p2, normalize(f.path))
48
+
49
+ # check a FileNotFoundError is raised if getting path/FileURL for a filesystem object that no longer exists
50
+ `rm #{@path2}`
51
+ assert_raises(MacTypes::FileNotFoundError) { f.to_s } # File not found.
52
+ assert_raises(MacTypes::FileNotFoundError) { f.to_file_url } # File not found.
53
+
54
+ assert_equal(MacTypes::Alias.path("/Library/Scripts/"), MacTypes::Alias.path("/Library/Scripts/"))
55
+ refute_equal(MacTypes::Alias.path("/Library/Scripts/"), MacTypes::Alias.path("/Applications/"))
56
+ end
57
+
58
+
59
+ def test_file_url
60
+
61
+ g = MacTypes::FileURL.path('/non/existent path')
62
+
63
+ assert_equal('/non/existent path', g.to_s)
64
+
65
+ assert_equal('furl', g.desc.type)
66
+ assert_equal('file://localhost/non/existent%20path', g.desc.data)
67
+
68
+ assert_equal('MacTypes::FileURL.path("/non/existent path")', g.to_file_url.inspect)
69
+
70
+ # check a not-found error is raised if getting Alias for a filesystem object that doesn't exist
71
+ assert_raises(MacTypes::FileNotFoundError) { g.to_alias } # File "/non/existent path" not found.
72
+
73
+ assert_equal(MacTypes::FileURL.path("/Library/Scripts/"), MacTypes::FileURL.path("/Library/Scripts/"))
74
+ refute_equal(MacTypes::FileURL.path("/Library/Scripts/"), MacTypes::FileURL.path("/Applications/"))
75
+ refute_equal(MacTypes::FileURL.path("/Library/Scripts/"), MacTypes::Alias.path("/Library/Scripts/"))
76
+ end
77
+ end