ruby_android_apk 0.7.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,228 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Android::Manifest do
4
+ describe Android::Manifest::Component do
5
+ describe "self.valid?" do
6
+ let(:elem) { REXML::Element.new('service') }
7
+ subject { Android::Manifest::Component.valid?(elem) }
8
+ context "with valid component element" do
9
+ it { should be_true }
10
+ end
11
+ context "with invalid component element" do
12
+ let(:elem) { REXML::Element.new('invalid-name') }
13
+ it { should be_false }
14
+ end
15
+ context "when some exception occurs in REXML::Element object" do
16
+ let(:elem) {
17
+ elem = stub(REXML::Element)
18
+ elem.stub(:name).and_raise(StandardError)
19
+ elem
20
+ }
21
+ it { should be_false }
22
+ end
23
+ end
24
+ describe '#metas' do
25
+ subject { Android::Manifest::Component.new(elem).metas }
26
+ context 'with valid component element has 2 meta elements' do
27
+ let(:elem) {
28
+ elem = REXML::Element.new('service')
29
+ elem << REXML::Element.new('meta-data')
30
+ elem << REXML::Element.new('meta-data')
31
+ elem
32
+ }
33
+ it { should have(2).item }
34
+ end
35
+ end
36
+ describe '#elem' do
37
+ subject { Android::Manifest::Component.new(elem).elem }
38
+ let(:elem) { REXML::Element.new('service') }
39
+ it { should eq elem }
40
+ end
41
+
42
+ describe Android::Manifest::Meta do
43
+ let(:elem) do
44
+ attrs = { 'name' => 'meta name', 'resource' => 'res', 'value' => 'val' }
45
+ elem = stub(REXML::Element, :attributes => attrs)
46
+ elem
47
+ end
48
+ subject { Android::Manifest::Meta.new(elem) }
49
+ its(:name) { should eq 'meta name' }
50
+ its(:resource) { should eq 'res' }
51
+ its(:value) { should eq 'val' }
52
+ end
53
+ end
54
+
55
+ describe Android::Manifest::IntentFilter do
56
+ describe '.parse' do
57
+ subject { Android::Manifest::IntentFilter.parse(elem) }
58
+ context 'assings "action" element' do
59
+ let(:elem) { REXML::Element.new('action') }
60
+ it { should be_instance_of Android::Manifest::IntentFilter::Action }
61
+ end
62
+ context 'assings "category" element' do
63
+ let(:elem) { REXML::Element.new('category') }
64
+ it { should be_instance_of Android::Manifest::IntentFilter::Category }
65
+ end
66
+ context 'assings "data" element' do
67
+ let(:elem) { REXML::Element.new('data') }
68
+ it { should be_instance_of Android::Manifest::IntentFilter::Data }
69
+ end
70
+ context 'assings unknown element' do
71
+ let(:elem) { REXML::Element.new('unknown') }
72
+ it { should be_nil }
73
+ end
74
+ end
75
+ end
76
+
77
+ context "with stub AXMLParser" do
78
+ let(:dummy_xml) {
79
+ xml = REXML::Document.new
80
+ xml << REXML::Element.new('manifest')
81
+ }
82
+ let(:manifest) { Android::Manifest.new('mock data') }
83
+
84
+ before do
85
+ parser = stub(Android::AXMLParser, :parse => dummy_xml)
86
+ Android::AXMLParser.stub(:new).and_return(parser)
87
+ end
88
+
89
+ describe "#use_parmissions" do
90
+ subject { manifest.use_permissions }
91
+ context "with valid 3 parmission elements" do
92
+ before do
93
+ 3.times do |i|
94
+ elem = REXML::Element.new("uses-permission")
95
+ elem.add_attribute 'name', "permission#{i}"
96
+ dummy_xml.root << elem
97
+ end
98
+ end
99
+ it { subject.should have(3).items }
100
+ it "should have permissions" do
101
+ subject.should include("permission0")
102
+ subject.should include("permission1")
103
+ subject.should include("permission2")
104
+ end
105
+ end
106
+ context "with no parmissions" do
107
+ it { should be_empty }
108
+ end
109
+ end
110
+
111
+ describe "#components" do
112
+ subject { manifest.components }
113
+ context "with valid parmission element" do
114
+ before do
115
+ app = REXML::Element.new('application')
116
+ activity = REXML::Element.new('activity')
117
+ app << activity
118
+ dummy_xml.root << app
119
+ end
120
+ it "should have components" do
121
+ subject.should have(1).items
122
+ end
123
+ it "should returns Component object" do
124
+ subject[0].should be_kind_of Android::Manifest::Component
125
+ end
126
+ end
127
+ context "with no components" do
128
+ it { should be_empty }
129
+ end
130
+ context 'with text element in intent-filter element. (issue #3)' do
131
+ before do
132
+ app = REXML::Element.new('application')
133
+ activity = REXML::Element.new('activity')
134
+ intent_filter = REXML::Element.new('intent-filter')
135
+ text = REXML::Text.new('sample')
136
+
137
+ intent_filter << text
138
+ activity << intent_filter
139
+ app << activity
140
+ dummy_xml.root << app
141
+ end
142
+ it "should have components" do
143
+ subject.should have(1).items
144
+ end
145
+ it { expect { subject }.to_not raise_error }
146
+ end
147
+ end
148
+ end
149
+
150
+ context "with real sample_AndroidManifest.xml data" do
151
+ let(:bin_xml_path){ File.expand_path(File.dirname(__FILE__) + '/data/sample_AndroidManifest.xml') }
152
+ let(:bin_xml){ File.open(bin_xml_path, 'rb') {|f| f.read } }
153
+ let(:manifest){ Android::Manifest.new(bin_xml) }
154
+
155
+ describe "#components" do
156
+ subject { manifest.components }
157
+ it { should be_kind_of Array }
158
+ it { subject[0].should be_kind_of Android::Manifest::Component }
159
+ end
160
+ describe "#package_name" do
161
+ subject { manifest.package_name }
162
+ it { should == "example.app.sample" }
163
+ end
164
+ describe "#version_code" do
165
+ subject { manifest.version_code}
166
+ it { should == 101 }
167
+ end
168
+ describe "#version_name" do
169
+ subject { manifest.version_name}
170
+ it { should == "1.0.1-malware2" }
171
+ end
172
+ describe "#min_sdk_ver" do
173
+ subject { manifest.min_sdk_ver}
174
+ it { should == 10 }
175
+ end
176
+ describe "#label" do
177
+ subject { manifest.label }
178
+ it { should == "@0x7f040001" }
179
+
180
+ context "with real apk file" do
181
+ let(:tmp_path){ File.expand_path(File.dirname(__FILE__) + '/data/sample.apk') }
182
+ let(:apk) { Android::Apk.new(tmp_path) }
183
+ let(:manifest){ apk.manifest }
184
+ subject { manifest.label }
185
+ it { should eq 'Sample' }
186
+ context 'when assign lang code' do
187
+ subject { manifest.label('ja') }
188
+ it { should eq 'Sample' }
189
+ end
190
+ end
191
+ context "with real new apk file" do
192
+ let(:tmp_path){ File.expand_path(File.dirname(__FILE__) + '/data/sample_new.apk') }
193
+ let(:apk) { Android::Apk.new(tmp_path) }
194
+ let(:manifest){ apk.manifest }
195
+ subject { manifest.label }
196
+ it { should eq 'My Application' }
197
+ end
198
+ end
199
+ describe "#doc" do
200
+ subject { manifest.doc }
201
+ it { should be_instance_of REXML::Document }
202
+ end
203
+ describe "#to_xml" do
204
+ let(:raw_xml){ str = <<EOS
205
+ <manifest xmlns:android='http://schemas.android.com/apk/res/android' android:versionCode='101' android:versionName='1.0.1-malware2' package='example.app.sample'>
206
+ <uses-sdk android:minSdkVersion='10'/>
207
+ <uses-permission android:name='android.permission.INTERNET'/>
208
+ <uses-permission android:name='android.permission.WRITE_EXTERNAL_STORAGE'/>
209
+ <application android:label='@0x7f040001' android:icon='@0x7f020000' android:debuggable='true'>
210
+ <activity android:label='@0x7f040001' android:name='example.app.sample.SampleActivity'>
211
+ <intent-filter>
212
+ <action android:name='android.intent.action.MAIN'/>
213
+ <category android:name='android.intent.category.LAUNCHER'/>
214
+ </intent-filter>
215
+ </activity>
216
+ </application>
217
+ </manifest>
218
+ EOS
219
+ str.strip
220
+ }
221
+
222
+ subject { manifest.to_xml }
223
+ it "should return correct xml string" do
224
+ subject.should == raw_xml
225
+ end
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,170 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
+
4
+ describe Android::Resource do
5
+ let(:res_data) { File.read(res_path) }
6
+ let(:resource) { Android::Resource.new(res_data) }
7
+
8
+ shared_examples_for 'a valid Android::Resource' do
9
+ subject { resource }
10
+ describe '#initialize' do
11
+ context 'assigns resources.arsc data' do
12
+ it { should be_instance_of Android::Resource }
13
+ end
14
+ end
15
+ its(:package_count) {should eq 1 }
16
+ describe '#strings' do
17
+ subject { resource.strings }
18
+ it { should have(7).items } # depends on sample_resources.arsc
19
+ it { should include 'Sample' }
20
+ it { should include 'Hello World, SampleActivity!' }
21
+ it { should include '日本語リソース' }
22
+ end
23
+ end
24
+ context 'with sample_resources.arsc data' do
25
+ let(:res_path) { File.expand_path(File.dirname(__FILE__) + '/data/sample_resources.arsc') }
26
+ it_behaves_like 'a valid Android::Resource'
27
+
28
+ end
29
+ context 'with sample_resources_utf16.arsc data' do
30
+ let(:res_path) { File.expand_path(File.dirname(__FILE__) + '/data/sample_resources_utf16.arsc') }
31
+ it_behaves_like 'a valid Android::Resource'
32
+ end
33
+
34
+ describe Android::Resource::ChunkHeader do
35
+ shared_examples_for 'a chunk header' do
36
+ its(:type) { should eq 20 }
37
+ its(:header_size) { should eq 244 }
38
+ its(:size) { should eq 1000 }
39
+ end
40
+ subject { Android::Resource::ChunkHeader.new(data, offset) }
41
+ context 'with no offset' do
42
+ let(:data) { "\x14\x00\xF4\x00\xE8\x03\x00\x00" } # [20, 244, 1000].pack('vvV')
43
+ let(:offset) { 0 }
44
+ it_behaves_like 'a chunk header'
45
+ end
46
+ context 'with 10byte offset' do
47
+ let(:data) { "\x00"*10 + "\x14\x00\xF4\x00\xE8\x03\x00\x00" } # [20, 244, 1000].pack('vvV')
48
+ let(:offset) { 10 }
49
+ it_behaves_like 'a chunk header'
50
+ end
51
+ end
52
+
53
+ describe Android::Resource::ResStringPool do
54
+ describe '.utf8_len' do
55
+ subject { Android::Resource::ResStringPool.utf8_len(data) }
56
+ context 'assigns 0x7F' do
57
+ let(:data) { "\x7f" }
58
+ it { should eq [0x7f, 1] }
59
+ end
60
+ context 'assigns x81x01' do
61
+ let(:data) { "\x81\x01" }
62
+ it { should eq [0x0101, 2] }
63
+ end
64
+ context 'assigns xffxff' do
65
+ let(:data) { "\xff\xff" }
66
+ it { should eq [0x7fff, 2] }
67
+ end
68
+ end
69
+ describe '#utf16_len' do
70
+ subject { Android::Resource::ResStringPool.utf16_len(data) }
71
+ context 'assigns x7fff' do
72
+ let(:data) { "\xff\x7f" }
73
+ it { should eq [0x7fff, 2] }
74
+ end
75
+ context 'assigns x8001,x0001' do
76
+ let(:data) { "\x01\x80\x01\x00" }
77
+ it { should eq [0x10001, 4] }
78
+ end
79
+ context 'assigns xffff,xffff' do
80
+ let(:data) { "\xff\xff\xff\xff" }
81
+ it 'should eq 0x7fff 0xffff' do
82
+ should eq [0x7fffffff, 4]
83
+ end
84
+ end
85
+ end
86
+
87
+ context 'with str_resources.arsc data' do
88
+ let(:res_data) { File.read(File.expand_path(File.dirname(__FILE__) + '/data/str_resources.arsc')) }
89
+ subject { resource }
90
+ describe 'about drawable resource' do
91
+ it 'hoge' do
92
+ table = resource.packages.first[1]
93
+ p table
94
+ table.type_strings.each_with_index do |type, id|
95
+ puts "[0x#{(id+1).to_s(16)}] #{type}"
96
+ end
97
+ puts "readable id:" + table.res_readable_id('@0x7f020000')
98
+ end
99
+ end
100
+ end
101
+ context 'with str_resources.arsc data' do
102
+ let(:res_data) { File.read(File.expand_path(File.dirname(__FILE__) + '/data/str_resources.arsc')) }
103
+ subject { resource }
104
+ describe '#packages' do
105
+ subject {resource.packages}
106
+ it { should be_instance_of Hash}
107
+ it { subject.size.should eq 1 }
108
+ end
109
+ describe 'ResTablePackage' do
110
+ subject { resource.packages.first[1] }
111
+ it { subject.type(1).should eq 'attr' }
112
+ it { subject.type(4).should eq 'string' }
113
+ it { subject.name.should eq 'com.example.sample.ruby_apk' }
114
+ end
115
+ describe '#find' do
116
+ it '@0x7f040000 should return "sample.ruby_apk"' do
117
+ subject.find('@0x7f040000').should eq 'sample application'
118
+ end
119
+ it '@string/app_name should return "sample.ruby_apk"' do
120
+ subject.find('@string/app_name').should eq 'sample application'
121
+ end
122
+ it '@string/hello_world should return "Hello world!"' do
123
+ subject.find('@string/hello_world').should eq 'Hello world!'
124
+ end
125
+ it '@string/app_name should return "sample.ruby_apk"' do
126
+ subject.find('@string/app_name').should eq 'sample application'
127
+ end
128
+ it '@string/app_name with {:lang => "ja"} should return "サンプルアプリ"' do
129
+ subject.find('@string/app_name', :lang => 'ja').should eq 'サンプルアプリ'
130
+ end
131
+ it '@string/hello_world with {:lang => "ja"} should return nil' do
132
+ subject.find('@string/hello_world', :lang => 'ja').should be_nil
133
+ end
134
+ context 'assigns not exist string resource id' do
135
+ it { expect {subject.find('@string/not_exist') }.to raise_error Android::NotFoundError }
136
+ it { expect {subject.find('@0x7f040033') }.to raise_error Android::NotFoundError }
137
+ end
138
+ context 'assigns not string resource id' do
139
+ it { subject.find('@layout/activity_main').should be_nil }
140
+ end
141
+ context 'assigns invalid format id' do
142
+ it '"@xxyyxxyy" should raise ArgumentError' do
143
+ expect{ subject.find('@xxyyxxyy') }.to raise_error(ArgumentError)
144
+ end
145
+ it '"@0xff112233445566" should raise ArgumentError' do
146
+ expect{ subject.find('@0xff112233445566') }.to raise_error(ArgumentError)
147
+ end
148
+ end
149
+ end
150
+ describe '#res_readable_id' do
151
+ it { subject.res_readable_id('@0x7f040000').should eq '@string/app_name' }
152
+ context 'assigns invalid type' do
153
+ it { expect{subject.res_readable_id('@0x7f0f0000')}.to raise_error Android::NotFoundError }
154
+ end
155
+ context 'assigns invalid key' do
156
+ it { expect{subject.res_readable_id('@0x7f040033')}.to raise_error Android::NotFoundError }
157
+ end
158
+ end
159
+ describe '#res_hex_id' do
160
+ it { subject.res_hex_id('@string/app_name').should eq '@0x7f040000' }
161
+ context 'assigns invalid type' do
162
+ it { expect{subject.res_readable_id('@not_exist/xxxx')}.to raise_error Android::NotFoundError }
163
+ end
164
+ context 'assigns invalid key' do
165
+ it { expect{subject.res_readable_id('@string/not_exist')}.to raise_error Android::NotFoundError }
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,4 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "RubyApk" do
4
+ end
@@ -0,0 +1,17 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'simplecov'
4
+ SimpleCov.start do
5
+ add_filter "/spec"
6
+ end
7
+ require 'rspec'
8
+ require 'ruby_apk'
9
+
10
+
11
+ # Requires supporting files with custom matchers and macros, etc,
12
+ # in ./support/ and its subdirectories.
13
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
14
+
15
+ RSpec.configure do |config|
16
+
17
+ end
@@ -0,0 +1,95 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Android::Utils do
4
+ let(:sample_apk_path) { File.expand_path(File.dirname(__FILE__) + '/data/sample.apk') }
5
+ let(:sample_new_apk_path) { File.expand_path(File.dirname(__FILE__) + '/data/sample_new.apk') }
6
+ let(:sample_dex_path) { File.expand_path(File.dirname(__FILE__) + '/data/sample_classes.dex') }
7
+ describe '.apk?' do
8
+ subject { Android::Utils.apk?(apk_path) }
9
+
10
+ context 'assigns apk file path' do
11
+ let(:apk_path) { sample_apk_path }
12
+ it { should be_true }
13
+ end
14
+ context 'assigns new apk file path' do
15
+ let(:apk_path) { sample_new_apk_path }
16
+ it { should be_true }
17
+ end
18
+ context 'assigns nil' do
19
+ let(:apk_path) { nil }
20
+ it { should be_false }
21
+ end
22
+ context 'assigns not exist path' do
23
+ let(:apk_path) { 'hogehoge' }
24
+ it { should be_false }
25
+ end
26
+ context 'assigns not apk file path' do
27
+ let(:apk_path) { __FILE__ }
28
+ it { should be_false }
29
+ end
30
+ end
31
+
32
+ describe '.elf?' do
33
+ subject { Android::Utils.elf?(data) }
34
+ context 'assigns data start with elf magic' do
35
+ let(:data) { "\x7fELF\xff\xff\xff" }
36
+ it { should be_true }
37
+ end
38
+ context 'assigns nil' do
39
+ let(:data) { nil }
40
+ it { should be_false }
41
+ end
42
+ context 'assigns not elf data' do
43
+ let(:data) { "\xff\xff\xff\xff\xff\xff" }
44
+ it { should be_false }
45
+ end
46
+ end
47
+
48
+ describe '.cert?' do
49
+ subject { Android::Utils.cert?(data) }
50
+ context 'assigns data start with x509 magic' do
51
+ let(:data) { "\x30\x82\xff\xff\xff" }
52
+ it { should be_true }
53
+ end
54
+ context 'assigns nil' do
55
+ let(:data) { nil }
56
+ it { should be_false }
57
+ end
58
+ context 'assigns not valid data' do
59
+ let(:data) { "\xff\xff\xff\xff\xff\xff" }
60
+ it { should be_false }
61
+ end
62
+ end
63
+
64
+ describe '.dex?' do
65
+ subject { Android::Utils.dex?(data) }
66
+ context 'assigns dex file data' do
67
+ let(:data) { File.read(sample_dex_path) }
68
+ it { should be_true }
69
+ end
70
+ context 'assigns nil' do
71
+ let(:data) { nil }
72
+ it { should be_false }
73
+ end
74
+ context 'assings not dex data' do
75
+ let(:data) { 'hogehoge' }
76
+ it { should be_false }
77
+ end
78
+ end
79
+ describe '.valid_dex?' do
80
+ subject { Android::Utils.valid_dex?(data) }
81
+ context 'assigns dex file data' do
82
+ let(:data) { File.read(sample_dex_path) }
83
+ it { should be_true }
84
+ end
85
+ context 'assigns nil' do
86
+ let(:data) { nil }
87
+ it { should be_false }
88
+ end
89
+ context 'assings not dex data' do
90
+ let(:data) { 'hogehoge' }
91
+ it { should be_false }
92
+ end
93
+ end
94
+ end
95
+