Messaging: Vendor chips, colorpicker, photoviewer, and vcard in-tree

Clone no longer depends on LineageOS gitlinks; the libraries used by the app live in this repo.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-29 06:19:53 +09:00
co-authored by Cursor
parent a6b23f0f3c
commit 49789fc4a5
239 changed files with 35551 additions and 4 deletions
+45
View File
@@ -0,0 +1,45 @@
// Copyright (C) 2010 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package {
default_team: "trendy_team_pixel_connectivity_bt",
default_applicable_licenses: ["Android-Apache-2.0"],
}
android_test {
name: "AndroidVCardTests",
certificate: "platform",
platform_apis: true,
test_suites: ["device-tests"],
srcs: ["src/**/*.java"],
libs: [
"android.test.runner.stubs.system",
"android.test.base.stubs.system",
"android.test.mock.stubs.system",
],
static_libs: [
"com.android.vcard",
"junit",
"androidx.test.ext.truth",
"androidx.test.rules",
"mockito-target",
"truth",
],
jacoco: {
include_filter: ["com.android.vcard.*"],
exclude_filter: ["com.android.vcard.tests.*"],
},
}
+32
View File
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
Run test with:
adb shell am instrument -w com.android.vcard.tests/android.test.InstrumentationTestRunner
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.vcard.tests"
android:sharedUserId="com.android.uid.test">
<application>
<uses-library android:name="android.test.runner" />
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.android.vcard.tests"
android:label="TestRunner letting users run each test including new one" />
</manifest>
+28
View File
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<configuration description="TestRunner letting users run each test including new one.">
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="AndroidVCardTests.apk" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
<option name="test-tag" value="AndroidVCardTests" />
<test class="com.android.tradefed.testtype.InstrumentationTest" >
<option name="package" value="com.android.vcard.tests" />
<option name="runner" value="android.test.InstrumentationTestRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>
@@ -0,0 +1,10 @@
BEGIN:VCARD
VERSION:2.1
N:bogus
URL:http://bogus.com/
ADR;HOME:;;Grindelberg 999;Hamburg;;99999;Deutschland
ADR;HOME:;;Hermann v. Brevern\
9999999\
Packstation 999;Hamburg;;99999;Deutschland
BDAY;VALUE=DATE:20081203
END:VCARD
@@ -0,0 +1,6 @@
BEGIN:VCARD
X-ANDROID-CUSTOM:custom_mime1;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15
X-ANDROID-CUSTOM:custom_mime2;a;b;c;d;e;f;g;h;i;j;k;l;m;n;o;p
X-ANDROID-CUSTOM:custom_mime3
X-ANDROID-CUSTOM:custom_mime4;z
END:VCARD
@@ -0,0 +1,5 @@
BEGIN:VCARD
VERSION:2.1
N:;A\;B\\;C\\\;;D;\:E;\\\\;
FN:A;B\C\;D:E\\
END:VCARD
@@ -0,0 +1,78 @@
BEGIN:VCARD
VERSION:2.1
N:name
FN:fullname
PHOTO;ENCODING=BASE64;TYPE=JPEG:
/9j/4QoPRXhpZgAATU0AKgAAAAgADQEOAAIAAAAPAAAAqgEPAAIAAAAHAAAAugEQAAIAAAAG
AAAAwgESAAMAAAABAAEAAAEaAAUAAAABAAAAyAEbAAUAAAABAAAA0AEoAAMAAAABAAIAAAEx
AAIAAAAOAAAA2AEyAAIAAAAUAAAA5gITAAMAAAABAAEAAIKYAAIAAAAOAAAA+odpAAQAAAAB
AAABhMSlAAcAAAB8AAABCAAABB4yMDA4MTAyOTEzNTUzMQAARG9Db01vAABEOTA1aQAAAABI
AAAAAQAAAEgAAAABRDkwNWkgVmVyMS4wMAAyMDA4OjEwOjI5IDEzOjU1OjQ3ACAgICAgICAg
ICAgICAAUHJpbnRJTQAwMzAwAAAABgABABQAFAACAQAAAAADAAAANAEABQAAAAEBAQAAAAEQ
gAAAAAAAEQkAACcQAAAPCwAAJxAAAAWXAAAnEAAACLAAACcQAAAcAQAAJxAAAAJeAAAnEAAA
AIsAACcQAAADywAAJxAAABvlAAAnEAAogpoABQAAAAEAAANqgp0ABQAAAAEAAANyiCIAAwAA
AAEAAgAAkAAABwAAAAQwMjIwkAMAAgAAABQAAAN6kAQAAgAAABQAAAOOkQEABwAAAAQBAgMA
kQIABQAAAAEAAAOikgEACgAAAAEAAAOqkgIABQAAAAEAAAOykgQACgAAAAEAAAO6kgUABQAA
AAEAAAPCkgcAAwAAAAEAAgAAkggAAwAAAAEAAAAAkgkAAwAAAAEAAAAAkgoABQAAAAEAAAPK
knwABwAAAAEAAAAAkoYABwAAABYAAAPSoAAABwAAAAQwMTAwoAEAAwAAAAEAAQAAoAIAAwAA
AAEAYAAAoAMAAwAAAAEASAAAoAUABAAAAAEAAAQAog4ABQAAAAEAAAPoog8ABQAAAAEAAAPw
ohAAAwAAAAEAAgAAohcAAwAAAAEAAgAAowAABwAAAAEDAAAAowEABwAAAAEBAAAApAEAAwAA
AAEAAAAApAIAAwAAAAEAAAAApAMAAwAAAAEAAAAApAQABQAAAAEAAAP4pAUAAwAAAAEAHQAA
pAYAAwAAAAEAAAAApAcAAwAAAAEAAAAApAgAAwAAAAEAAAAApAkAAwAAAAEAAAAApAoAAwAA
AAEAAAAApAwAAwAAAAEAAgAAAAAAAAAAAFMAACcQAAABXgAAAGQyMDA4OjEwOjI5IDEzOjU1
OjMxADIwMDg6MTA6MjkgMTM6NTU6NDcAAAApiAAAGwAAAAKyAAAAZAAAAV4AAABkAAAAAAAA
AGQAAAAlAAAACgAADpIAAAPoAAAAAAAAAAAyMDA4MTAyOTEzNTUzMQAAICoAAAAKAAAq4gAA
AAoAAAAAAAAAAQACAAEAAgAAAARSOTgAAAIABwAAAAQwMTAwAAAAAAAGAQMAAwAAAAEABgAA
ARoABQAAAAEAAARsARsABQAAAAEAAAR0ASgAAwAAAAEAAgAAAgEABAAAAAEAAAR8AgIABAAA
AAEAAAWLAAAAAAAAAEgAAAABAAAASAAAAAH/2P/bAIQAIBYYHBgUIBwaHCQiICYwUDQwLCww
YkZKOlB0Znp4cmZwboCQuJyAiK6KbnCg2qKuvsTO0M58muLy4MjwuMrOxgEiJCQwKjBeNDRe
xoRwhMbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbG
/8AAEQgAeACgAwEhAAIRAQMRAf/EAaIAAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKCxAA
AgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkK
FhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWG
h4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl
5ufo6erx8vP09fb3+Pn6AQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgsRAAIBAgQEAwQH
BQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBka
JicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKT
lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz
9PX29/j5+v/aAAwDAQACEQMRAD8AFFSqKkZIoqRVpgSKKeBTEOApwFADsUYpgIRSEUANIppF
ICNhUTCgCMio2FICJhULCgC0oqVaAJFFSqKBkgFOApiHCnCgB2KMUCENJQA0imEUDGMKiYUA
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
END:VCARD
@@ -0,0 +1,44 @@
BEGIN:VCARD
VERSION:2.1
FN:boogie
N:boogie
PHOTO;ENCODING=BASE64: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
fGh4i/V4q4YNEfoiwAAAABJRU5ErkJggg==
TEL;TYPE=WORK:+5555555
TEL;TYPE=CELL:+5555556
EMAIL;TYPE=INTERNET:forrestgump@walladalla.com
END:VCARD
@@ -0,0 +1,107 @@
BEGIN:VCARD
VERSION:2.1
N:Gump;Forrest;Hoge;Pos;Tao
FN:Joe Due
ORG:Gump Shrimp Co.;Sales Dept.\;Manager;Fish keeper
ROLE:Fish Cake Keeper!
X-CLASS:PUBLIC
TITLE:Shrimp Man
TEL;WORK;VOICE:(111) 555-1212
TEL;HOME;VOICE:(404) 555-1212
TEL;FAX:(404) 555-1212P*#55
TEL;CELL:0311111111
TEL;VIDEO:0322222222
TEL;VOICE:0333333333
ADR;WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America
LABEL;WORK;ENCODING=QUOTED-PRINTABLE:100 Waters Edge=0D=0ABaytown, LA 30314=0D=0AUnited States of America
ADR;HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America
LABEL;HOME;ENCODING=QUOTED-PRINTABLE:42 Plantation St.=0D=0A=
Baytown, LA 30314=0D=0A=
United States of America
EMAIL;PREF;INTERNET:forrestgump@walladalla.com
EMAIL;CELL:cell@example.com
NOTE:The following note is the example from RFC 2045.
NOTE;ENCODING=QUOTED-PRINTABLE:Now's the time =
for all folk to come=
to the aid of their country.
PHOTO;ENCODING=BASE64;TYPE=JPEG:
/9j/4QoPRXhpZgAATU0AKgAAAAgADQEOAAIAAAAPAAAAqgEPAAIAAAAHAAAAugEQAAIAAAAG
AAAAwgESAAMAAAABAAEAAAEaAAUAAAABAAAAyAEbAAUAAAABAAAA0AEoAAMAAAABAAIAAAEx
AAIAAAAOAAAA2AEyAAIAAAAUAAAA5gITAAMAAAABAAEAAIKYAAIAAAAOAAAA+odpAAQAAAAB
AAABhMSlAAcAAAB8AAABCAAABB4yMDA4MTAyOTEzNTUzMQAARG9Db01vAABEOTA1aQAAAABI
AAAAAQAAAEgAAAABRDkwNWkgVmVyMS4wMAAyMDA4OjEwOjI5IDEzOjU1OjQ3ACAgICAgICAg
ICAgICAAUHJpbnRJTQAwMzAwAAAABgABABQAFAACAQAAAAADAAAANAEABQAAAAEBAQAAAAEQ
gAAAAAAAEQkAACcQAAAPCwAAJxAAAAWXAAAnEAAACLAAACcQAAAcAQAAJxAAAAJeAAAnEAAA
AIsAACcQAAADywAAJxAAABvlAAAnEAAogpoABQAAAAEAAANqgp0ABQAAAAEAAANyiCIAAwAA
AAEAAgAAkAAABwAAAAQwMjIwkAMAAgAAABQAAAN6kAQAAgAAABQAAAOOkQEABwAAAAQBAgMA
kQIABQAAAAEAAAOikgEACgAAAAEAAAOqkgIABQAAAAEAAAOykgQACgAAAAEAAAO6kgUABQAA
AAEAAAPCkgcAAwAAAAEAAgAAkggAAwAAAAEAAAAAkgkAAwAAAAEAAAAAkgoABQAAAAEAAAPK
knwABwAAAAEAAAAAkoYABwAAABYAAAPSoAAABwAAAAQwMTAwoAEAAwAAAAEAAQAAoAIAAwAA
AAEAYAAAoAMAAwAAAAEASAAAoAUABAAAAAEAAAQAog4ABQAAAAEAAAPoog8ABQAAAAEAAAPw
ohAAAwAAAAEAAgAAohcAAwAAAAEAAgAAowAABwAAAAEDAAAAowEABwAAAAEBAAAApAEAAwAA
AAEAAAAApAIAAwAAAAEAAAAApAMAAwAAAAEAAAAApAQABQAAAAEAAAP4pAUAAwAAAAEAHQAA
pAYAAwAAAAEAAAAApAcAAwAAAAEAAAAApAgAAwAAAAEAAAAApAkAAwAAAAEAAAAApAoAAwAA
AAEAAAAApAwAAwAAAAEAAgAAAAAAAAAAAFMAACcQAAABXgAAAGQyMDA4OjEwOjI5IDEzOjU1
OjMxADIwMDg6MTA6MjkgMTM6NTU6NDcAAAApiAAAGwAAAAKyAAAAZAAAAV4AAABkAAAAAAAA
AGQAAAAlAAAACgAADpIAAAPoAAAAAAAAAAAyMDA4MTAyOTEzNTUzMQAAICoAAAAKAAAq4gAA
AAoAAAAAAAAAAQACAAEAAgAAAARSOTgAAAIABwAAAAQwMTAwAAAAAAAGAQMAAwAAAAEABgAA
ARoABQAAAAEAAARsARsABQAAAAEAAAR0ASgAAwAAAAEAAgAAAgEABAAAAAEAAAR8AgIABAAA
AAEAAAWLAAAAAAAAAEgAAAABAAAASAAAAAH/2P/bAIQAIBYYHBgUIBwaHCQiICYwUDQwLCww
YkZKOlB0Znp4cmZwboCQuJyAiK6KbnCg2qKuvsTO0M58muLy4MjwuMrOxgEiJCQwKjBeNDRe
xoRwhMbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbG
/8AAEQgAeACgAwEhAAIRAQMRAf/EAaIAAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKCxAA
AgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkK
FhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWG
h4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl
5ufo6erx8vP09fb3+Pn6AQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgsRAAIBAgQEAwQH
BQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBka
JicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKT
lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz
9PX29/j5+v/aAAwDAQACEQMRAD8AFFSqKkZIoqRVpgSKKeBTEOApwFADsUYpgIRSEUANIppF
ICNhUTCgCMio2FICJhULCgC0oqVaAJFFSqKBkgFOApiHCnCgB2KMUCENJQA0imEUDGMKiYUA
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
X-ATTRIBUTE:Some String
BDAY:19800101
GEO:35.6563854,139.6994233
URL:http://www.example.com/
REV:20080424T195243Z
END:VCARD
+5
View File
@@ -0,0 +1,5 @@
BEGIN:VCARD
VERSION:2.1
X-ANDROID-CUSTOM:vnd.android.cursor.item/nickname;Nick;1;;;;;;;;;;;;;
X-GOOGLE-TALK:hhh@gmail.com
END:VCARD
@@ -0,0 +1,10 @@
BEGIN:vCard
VERSION:2.1
UID:357
N:;Conference Call
FN:Conference Call
# This line must be ignored.
NOTE;ENCODING=QUOTED-PRINTABLE:This is an (sharp ->=
#<- sharp) example. This message must NOT be ignored.
# This line must be ignored too.
END:vCard
@@ -0,0 +1,7 @@
BEGIN:VCARD
VERSION:2.1
N:;Omega;;;
EMAIL;INTERNET:"Omega"
<omega@example.com>
FN:Omega
END:VCARD
@@ -0,0 +1,6 @@
BEGIN:VCARD
VERSION:2.1
N;CHARSET=SHIFT_JIS:安藤ロイド;;;;
SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:アンドウロイド;;;;
TEL;PREF;VOICE:0300000000
END:VCARD
@@ -0,0 +1,10 @@
BEGIN:VCARD
VERSION:2.1
FN;CHARSET=SHIFT_JIS:安藤 ロイド 1
N;CHARSET=SHIFT_JIS:安藤;ロイド1;;;
SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:アンドウ;ロイド1;;;
ADR;HOME;CHARSET=SHIFT_JIS;ENCODING=QUOTED-PRINTABLE:;=93=8C=8B=9E=93=73=
=8F=61=92=4A=8B=E6=8D=F7=8B=75=92=AC26-1=83=5A=83=8B=83=8A=83=41=83=93=
=83=5E=83=8F=81=5B6=8A=4B;;;;150-8512;
NOTE;CHARSET=SHIFT_JIS;ENCODING=QUOTED-PRINTABLE:=83=81=83=82
END:VCARD
@@ -0,0 +1,5 @@
BEGIN:VCARD
VERSION:2.1
FN;CHARSET=SHIFT_JIS:ˆÉ”\ Œ\ˆê ˆÉ—\
N;CHARSET=SHIFT_JIS:ˆÉ”\;Œ\ˆê;ˆÉ—\;;
END:VCARD
@@ -0,0 +1,7 @@
BEGIN:VCARD
VERSION:2.1
N:name
FN:fullname
PHOTO;ENCODING=BASE64;TYPE=JPEG:qgEPAAIAAAAHAAAAugEQAAIAAAAG:ASDF==
END:VCARD
@@ -0,0 +1,33 @@
BEGIN:VCARD
VERSION:2.1
N;CHARSET=SHIFT_JIS:安藤ロイド3;;;;
SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:アンドウロイド3;;;;
TEL;X-NEC-SECRET:9
TEL;X-NEC-HOTEL:10
TEL;X-NEC-SCHOOL:11
TEL;HOME;FAX:12
END:VCARD
BEGIN:VCARD
VERSION:2.1
N;CHARSET=SHIFT_JIS:安藤ロイド4;;;;
SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:アンドウロイド4;;;;
TEL;MODEM:13
TEL;PAGER:14
TEL;X-NEC-FAMILY:15
TEL;X-NEC-GIRL:16
END:VCARD
BEGIN:VCARD
VERSION:2.1
N;CHARSET=SHIFT_JIS:安藤ロイド5;;;;
SOUND;X-IRMC-N;CHARSET=SHIFT_JIS:アンドウロイド5;;;;
TEL;X-NEC-BOY:17
TEL;X-NEC-FRIEND:18
TEL;X-NEC-PHS:19
TEL;X-NEC-RESTAURANT:20
END:VCARD
+13
View File
@@ -0,0 +1,13 @@
BEGIN:VCARD
VERSION:2.1
N:parent
BEGIN:VCARD
VERSION:2.1
N:nest1
END:VCARD
BEGIN:VCARD
VERSION:2.1
N:nest2
END:VCARD
TEL:1
END:VCARD
@@ -0,0 +1,16 @@
Content-Type: text/x-vcard
CHARSET=utf-8
profile=vCard
BEGIN:VCARD
VERSION:2.1
N:parent
BEGIN:VCARD
VERSION:2.1
N:nest1
END:VCARD
BEGIN:VCARD
VERSION:2.1
N:nest2
END:VCARD
TEL:1
END:VCARD
@@ -0,0 +1,6 @@
BEGIN:VCARD
VERSION:2.1
FN:Normal Guy
ORG:Company;Organization;Devision;Room;Sheet No.
TITLE:Excellent Janitor
END:VCARD
@@ -0,0 +1,15 @@
BEGIN:VCARD
VERSION:2.1
FN:Smith
TEL;HOME:1
TEL;WORK;PREF:2
TEL;ISDN:3
EMAIL;PREF;HOME:test@example.com
EMAIL;CELL;PREF:test2@examination.com
ORG:Company
TITLE:Engineer
ORG:Mystery
TITLE:Blogger
ORG:Poetry
TITLE:Poet
END:VCARD
@@ -0,0 +1,3 @@
BEGIN:VCARD
N:Ando;Roid;
END:VCARD
@@ -0,0 +1,3 @@
BEGIN:VCARD
FN:Ando Roid
END:VCARD
@@ -0,0 +1,4 @@
BEGIN:VCARD
N:Ando;Roid;
FN:Ando Roid
END:VCARD
+6
View File
@@ -0,0 +1,6 @@
BEGIN:VCARD
VERSION:2.1
FN:Android
X-SIP:888
X-SIP:sip:90-180-360
END:VCARD
@@ -0,0 +1,6 @@
BEGIN:VCARD
VERSION:2.1
FN:Nice Guy
TITLE:Cool Title
ORG:Marverous;Perfect;Great;Good;Bad;Poor
END:VCARD
@@ -0,0 +1,10 @@
BEGIN:VCARD
VERSION:2.1
N:Example;;;;
FN:Example
ANNIVERSARY;VALUE=DATE:20091010
AGENT:Invalid line which must be handled correctly.
X-CLASS:PUBLIC
X-REDUCTION:
X-NO:
END:VCARD
@@ -0,0 +1,42 @@
BEGIN:VCARD
VERSION:2.1
N:Ando;Roid;
PHOTO;ENCODING=BASE64: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
fGh4i/V4q4YNEfoiwAAAABJRU5ErkJggg==
X-ANDROID-CUSTOM:vnd.android.cursor.item/contact_event;1999-07-10;1;;;;;;;;;;;;;
BDAY:1975-08-20
END:VCARD
@@ -0,0 +1,9 @@
BEGIN:VCARD
VERSION:2.1
N:Ando;Roid;
ADR;X-custom:pobox;street
TEL;X-CuStoMpRop:1
TEL;custompropertywithoutx:2
EMAIL;X-cUstomPrOperty:email@example.com
EMAIL;CUSTOMPROPERTYWITHOUTX:email2@example.com
END:VCARD
@@ -0,0 +1,8 @@
BEGIN:VCARD
VERSION:3.0
N:Familyname;Givenname;;;
FN:Givenname Familyname
ADR;TYPE=WORK:;;1010 Technology Pkwy\, Silicon City\, Somecountry;;;;
ADR;TYPE=X-Other:;;123 Main St\, Anytown\, Anywhere;;;;
ADR;TYPE=X-School:;;112358 Academic Lane\, College Town\, Someplace Great;;;;
END:VCARD
@@ -0,0 +1,5 @@
BEGIN:VCARD
VERSION:3.0
N;TYPE=PREF,HOME:F;G;M;;
TEL;TYPE="COMMA,SEPARATED:INSIDE.DQUOTE",PREF:1
END:VCARD
@@ -0,0 +1,107 @@
BEGIN:VCARD
VERSION:3.0
N:Gump;Forrest;Hoge;Pos;Tao
FN:Joe Due
ORG:Gump Shrimp Co.;Sales Dept.\;Manager;Fish keeper
ROLE:Fish Cake Keeper!
X-CLASS:PUBLIC
TITLE:Shrimp Man
TEL;WORK;VOICE:(111) 555-1212
TEL;HOME;VOICE:(404) 555-1212
TEL;FAX:(404) 555-1212P*#55
TEL;CELL:0311111111
TEL;VIDEO:0322222222
TEL;VOICE:0333333333
ADR;WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America
LABEL;WORK;ENCODING=QUOTED-PRINTABLE:100 Waters Edge=0D=0ABaytown, LA 30314=0D=0AUnited States of America
ADR;HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America
LABEL;HOME;ENCODING=QUOTED-PRINTABLE:42 Plantation St.=0D=0A=
Baytown, LA 30314=0D=0A=
United States of America
EMAIL;PREF;INTERNET:forrestgump@walladalla.com
EMAIL;CELL:cell@example.com
NOTE:The following note is the example from RFC 2045.
NOTE;ENCODING=QUOTED-PRINTABLE:Now's the time =
for all folk to come=
to the aid of their country.
PHOTO;ENCODING=BASE64;TYPE=JPEG:
/9j/4QoPRXhpZgAATU0AKgAAAAgADQEOAAIAAAAPAAAAqgEPAAIAAAAHAAAAugEQAAIAAAAG
AAAAwgESAAMAAAABAAEAAAEaAAUAAAABAAAAyAEbAAUAAAABAAAA0AEoAAMAAAABAAIAAAEx
AAIAAAAOAAAA2AEyAAIAAAAUAAAA5gITAAMAAAABAAEAAIKYAAIAAAAOAAAA+odpAAQAAAAB
AAABhMSlAAcAAAB8AAABCAAABB4yMDA4MTAyOTEzNTUzMQAARG9Db01vAABEOTA1aQAAAABI
AAAAAQAAAEgAAAABRDkwNWkgVmVyMS4wMAAyMDA4OjEwOjI5IDEzOjU1OjQ3ACAgICAgICAg
ICAgICAAUHJpbnRJTQAwMzAwAAAABgABABQAFAACAQAAAAADAAAANAEABQAAAAEBAQAAAAEQ
gAAAAAAAEQkAACcQAAAPCwAAJxAAAAWXAAAnEAAACLAAACcQAAAcAQAAJxAAAAJeAAAnEAAA
AIsAACcQAAADywAAJxAAABvlAAAnEAAogpoABQAAAAEAAANqgp0ABQAAAAEAAANyiCIAAwAA
AAEAAgAAkAAABwAAAAQwMjIwkAMAAgAAABQAAAN6kAQAAgAAABQAAAOOkQEABwAAAAQBAgMA
kQIABQAAAAEAAAOikgEACgAAAAEAAAOqkgIABQAAAAEAAAOykgQACgAAAAEAAAO6kgUABQAA
AAEAAAPCkgcAAwAAAAEAAgAAkggAAwAAAAEAAAAAkgkAAwAAAAEAAAAAkgoABQAAAAEAAAPK
knwABwAAAAEAAAAAkoYABwAAABYAAAPSoAAABwAAAAQwMTAwoAEAAwAAAAEAAQAAoAIAAwAA
AAEAYAAAoAMAAwAAAAEASAAAoAUABAAAAAEAAAQAog4ABQAAAAEAAAPoog8ABQAAAAEAAAPw
ohAAAwAAAAEAAgAAohcAAwAAAAEAAgAAowAABwAAAAEDAAAAowEABwAAAAEBAAAApAEAAwAA
AAEAAAAApAIAAwAAAAEAAAAApAMAAwAAAAEAAAAApAQABQAAAAEAAAP4pAUAAwAAAAEAHQAA
pAYAAwAAAAEAAAAApAcAAwAAAAEAAAAApAgAAwAAAAEAAAAApAkAAwAAAAEAAAAApAoAAwAA
AAEAAAAApAwAAwAAAAEAAgAAAAAAAAAAAFMAACcQAAABXgAAAGQyMDA4OjEwOjI5IDEzOjU1
OjMxADIwMDg6MTA6MjkgMTM6NTU6NDcAAAApiAAAGwAAAAKyAAAAZAAAAV4AAABkAAAAAAAA
AGQAAAAlAAAACgAADpIAAAPoAAAAAAAAAAAyMDA4MTAyOTEzNTUzMQAAICoAAAAKAAAq4gAA
AAoAAAAAAAAAAQACAAEAAgAAAARSOTgAAAIABwAAAAQwMTAwAAAAAAAGAQMAAwAAAAEABgAA
ARoABQAAAAEAAARsARsABQAAAAEAAAR0ASgAAwAAAAEAAgAAAgEABAAAAAEAAAR8AgIABAAA
AAEAAAWLAAAAAAAAAEgAAAABAAAASAAAAAH/2P/bAIQAIBYYHBgUIBwaHCQiICYwUDQwLCww
YkZKOlB0Znp4cmZwboCQuJyAiK6KbnCg2qKuvsTO0M58muLy4MjwuMrOxgEiJCQwKjBeNDRe
xoRwhMbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbG
/8AAEQgAeACgAwEhAAIRAQMRAf/EAaIAAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKCxAA
AgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkK
FhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWG
h4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl
5ufo6erx8vP09fb3+Pn6AQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgsRAAIBAgQEAwQH
BQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBka
JicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKT
lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz
9PX29/j5+v/aAAwDAQACEQMRAD8AFFSqKkZIoqRVpgSKKeBTEOApwFADsUYpgIRSEUANIppF
ICNhUTCgCMio2FICJhULCgC0oqVaAJFFSqKBkgFOApiHCnCgB2KMUCENJQA0imEUDGMKiYUA
RtUbUgIWqJhQBZSpFoAlWpVoGPFPFMQ7tSK2ODQA4yKO9HmKe9FxAzDHFIOlAAaYaAGNUTUD
ImqNqQETVE1AE6VKKAJFNSqaAHg08GmANIFFQM5Y5qJMBuT60ZNQIcrkVYSQMKuLGKaaasQx
qiagZE1RtSAjaomoAkQ1KpoAlU1IpoAkU07OBTArO+5qkV12Y71lfUBmaKkCRSuznrTFba2a
oCwGyM0E1qIjY1GxoGRNUZNICNqiagByGplNAEimpFNMB4YDvSucpxSYEIU04KazsAu1qArU
WELtPpTSposBNETt5pxNaoCNjUbGgCNjUZoGRtUTUgFU1KpoAkBqQHigCFnO7rUqOdlZp6gA
c+tODn1pXAXzD60eYfWncQvmNSGQ07gOMhCVEJGz1ptgS5yKYxqwGE1GxoAiamGkMapqVTQB
Kpp+eKAICfmqWM/Kaz6gANOBqQFzRmmAuaTNACsfkqMHmm9wJs8U0mtRDGNRsaAI2phpDI1N
SqaAJFNSA8UCISfmqSM/Kaz6jAHmnA1ICg0uaAFzSZpgKx+SmDrTe4E2eKaTWoiMmmMaAIzT
DSGRKakU0ASKaeDTERseakjPyms+oxAacDUgOBpc0gFzSZpgOY/KKYv3qrqIlpprQBjGoyaA
GGmmkMgU1IppgPBqQGgQu0Gn4wvFKwEQpwNZDHZpc0ALmigRKBleaQKBWtgA001QDGqM0gGm
mGkMrqakBoAepp4NMRIDTwaAE2A008GokgHxjd1pzKFpW0uAg5NSBBTirgOpDWgDTTTQAw0w
0gGGmmgZWBp4pASKaeDTEOBp4NADwajbrUyBEkXWnSUdAGr1qeiAMSkNWAhphoAaaYaQDDTT
SGVRTwaYDxTwaBDwaeDQA4GlK5oauIeo20pGaLaAKqgU6hKwBSGmAhphoAaaYaQxhpppDKgN
PFMB4p4oEPFOBpgPBp4NAhwpwoAWloAKSgBDTTQMYaYaQDTTTSGA/9n/2wCEAAoHBwgHBgoI
CAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9
PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7
Ozs7Ozs7Ozs7Ozs7O//AABEIAEgAYAMBIQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAA
AQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNC
scEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hp
anN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS
09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcI
CQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVi
ctEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4
eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY
2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AJ7SLgcVr20I4rNFGvbQAAHFaEUX
SrQi5HCMdKk8oY6VSJYx4hjpVaWMelAFC4iGDxWPdR8mkxmRdxjBrEvI+tZjN20xtHNbNqAc
UIDXg6Cr0WKtCY8XKQOyzOB3FKNWsyceZ+lS6sY6NkjvPSdwImBHUmmy4q076oCjOODWPdgc
0MpGPdAYNYl4o5rNjNKzkyorZtXxihAa1vIDip7m9Frb7/4jwKcnyxbEzN3ieJppZsyZ4U1H
urzZau4mWVlNrGk0UuWPVa1YroXEIkHfrXZh5W90RWncAHmsi6bJNdQ0ZNw3BrGuiMGs2Mks
puBzWzbzdOaEBeOpR2oUtkk9hTru7iuo4m8wgemKyqTi04sBsfkEf68j8KlUQZz9o/SuZRj3
JYriAji4/Sp7W6htbV2aXcu70ramoxle4gN7HcIXjbis+4k5NdaaauhmVcv1rHuW61DGiG1m
6c1s20/TmgAv5vmj57VKk3+ixnPc1xVV70h9CVJuOtSrL71hFgxzScUkkn+iY/2q1i9xDrGT
9y31pJ5Otd1L+GhMy7mTrWXO2SapjRn28vTmta3nxjmgGOvJd2w1Kkv+ipz/ABGuOoveYdCe
ObjrU6y5rlsA8ycUksn+ij/eNaw6iJLNsW59zTJn6816FP4EJmbO+Saz5m602UjIgk4HNadv
LwKaBl+MpIMOMipp490SCJeF7CoqQvF2JuRqWQ4YEGrSiQJuKnHrXByMpki73GFBNXIoh9n2
SrnnOK6MPTbd3sSwIVF2qMCqkzHmuy1lYRnTHrVGWpZaMKB+BWlbycYoQM0IZDxzV+GU8c1a
IYy5Y+dnHatAsfsAHfArmS1mPoh1gT8x9qtk1rQX7tCe5DIapzGtGBQm71SlqGWjnIH6Vowt
zmhAy/E3vV6F6tEMuxlWIyAfrVxCCAO1VZEEyYA4AApxNGwyJ+lVJRUsaKMw61SlFQzRAP/Z
X-ATTRIBUTE:Some String
BDAY:19800101
GEO:35.6563854,139.6994233
URL:http://www.example.com/
REV:20080424T195243Z
END:VCARD
@@ -0,0 +1,104 @@
BEGIN:VCARD␍
VERSION:3.0␍
N:Smith;Bob;;;␍
FN:Bob Smith␍
ORG:Smith Auto Repair;␍
item1.EMAIL;type=INTERNET;type=pref:bob@smithauto.com␍
TEL;type=CELL;type=VOICE;type=pref:(650) 555-1212␍
item2.URL;type=pref:www.smithauto.com␍
item2.X-ABLabel:_$!<HomePage>!$_␍
PHOTO;ENCODING=b;TYPE=JPEG:/9j/4AAQSkZJRgABAQAAAQABAAD/4gxYSUNDX1BST0ZJTEUA␍
AQEAAAxITGlubwIQAABtbnRyUkdCIFhZWiAHzgACAAkABgAxAABhY3NwTVNGVAAAAABJRUMgc1␍
JHQgAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLUhQICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA␍
AAAAAAAAAAAAAAAAAAAAAAAAAAAAABFjcHJ0AAABUAAAADNkZXNjAAABhAAAAGx3dHB0AAAB8A␍
AAABRia3B0AAACBAAAABRyWFlaAAACGAAAABRnWFlaAAACLAAAABRiWFlaAAACQAAAABRkbW5k␍
AAACVAAAAHBkbWRkAAACxAAAAIh2dWVkAAADTAAAAIZ2aWV3AAAD1AAAACRsdW1pAAAD+AAAAB␍
RtZWFzAAAEDAAAACR0ZWNoAAAEMAAAAAxyVFJDAAAEPAAACAxnVFJDAAAEPAAACAxiVFJDAAAE␍
PAAACAx0ZXh0AAAAAENvcHlyaWdodCAoYykgMTk5OCBIZXdsZXR0LVBhY2thcmQgQ29tcGFueQ␍
AAZGVzYwAAAAAAAAASc1JHQiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAABJzUkdCIElFQzYxOTY2␍
LTIuMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWF␍
laIAAAAAAAAPNRAAEAAAABFsxYWVogAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABvogAAOPUA␍
AAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAAJKAAAA+EAAC2z2Rlc2MAAAAAAAAAFk␍
lFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAFklFQyBodHRwOi8vd3d3LmllYy5jaAAA␍
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkZXNjAAAAAAAAAC␍
5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAtIHNSR0IAAAAAAAAAAAAA␍
AC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAtIHNSR0IAAAAAAAAAAA␍
AAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAsUmVmZXJlbmNlIFZpZXdpbmcgQ29uZGl0aW9uIGlu␍
IElFQzYxOTY2LTIuMQAAAAAAAAAAAAAALFJlZmVyZW5jZSBWaWV3aW5nIENvbmRpdGlvbiBpbi␍
BJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZpZXcAAAAAABOk/gAUXy4A␍
EM8UAAPtzAAEEwsAA1yeAAAAAVhZWiAAAAAAAEwJVgBQAAAAVx/nbWVhcwAAAAAAAAABAAAAAA␍
AAAAAAAAAAAAAAAAAAAo8AAAACc2lnIAAAAABDUlQgY3VydgAAAAAAAAQAAAAABQAKAA8AFAAZ␍
AB4AIwAoAC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYAiwCQAJUAmgCfAK␍
QAqQCuALIAtwC8AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7AQEBBwENARMBGQEfASUBKwEyATgB␍
PgFFAUwBUgFZAWABZwFuAXUBfAGDAYsBkgGaAaEBqQGxAbkBwQHJAdEB2QHhAekB8gH6AgMCDA␍
IUAh0CJgIvAjgCQQJLAlQCXQJnAnECegKEAo4CmAKiAqwCtgLBAssC1QLgAusC9QMAAwsDFgMh␍
Ay0DOANDA08DWgNmA3IDfgOKA5YDogOuA7oDxwPTA+AD7AP5BAYEEwQgBC0EOwRIBFUEYwRxBH␍
4EjASaBKgEtgTEBNME4QTwBP4FDQUcBSsFOgVJBVgFZwV3BYYFlgWmBbUFxQXVBeUF9gYGBhYG␍
JwY3BkgGWQZqBnsGjAadBq8GwAbRBuMG9QcHBxkHKwc9B08HYQd0B4YHmQesB78H0gflB/gICw␍
gfCDIIRghaCG4IggiWCKoIvgjSCOcI+wkQCSUJOglPCWQJeQmPCaQJugnPCeUJ+woRCicKPQpU␍
CmoKgQqYCq4KxQrcCvMLCwsiCzkLUQtpC4ALmAuwC8gL4Qv5DBIMKgxDDFwMdQyODKcMwAzZDP␍
MNDQ0mDUANWg10DY4NqQ3DDd4N+A4TDi4OSQ5kDn8Omw62DtIO7g8JDyUPQQ9eD3oPlg+zD88P␍
7BAJECYQQxBhEH4QmxC5ENcQ9RETETERTxFtEYwRqhHJEegSBxImEkUSZBKEEqMSwxLjEwMTIx␍
NDE2MTgxOkE8UT5RQGFCcUSRRqFIsUrRTOFPAVEhU0FVYVeBWbFb0V4BYDFiYWSRZsFo8WshbW␍
FvoXHRdBF2UXiReuF9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpRGncanhrFGu␍
wbFBs7G2MbihuyG9ocAhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4WHkAeah6UHr4e6R8THz4f␍
aR+UH78f6iAVIEEgbCCYIMQg8CEcIUghdSGhIc4h+yInIlUigiKvIt0jCiM4I2YjlCPCI/AkHy␍
RNJHwkqyTaJQklOCVoJZclxyX3JicmVyaHJrcm6CcYJ0kneierJ9woDSg/KHEooijUKQYpOClr␍
KZ0p0CoCKjUqaCqbKs8rAis2K2krnSvRLAUsOSxuLKIs1y0MLUEtdi2rLeEuFi5MLoIuty7uLy␍
QvWi+RL8cv/jA1MGwwpDDbMRIxSjGCMbox8jIqMmMymzLUMw0zRjN/M7gz8TQrNGU0njTYNRM1␍
TTWHNcI1/TY3NnI2rjbpNyQ3YDecN9c4FDhQOIw4yDkFOUI5fzm8Ofk6Njp0OrI67zstO2s7qj␍
voPCc8ZTykPOM9Ij1hPaE94D4gPmA+oD7gPyE/YT+iP+JAI0BkQKZA50EpQWpBrEHuQjBCckK1␍
QvdDOkN9Q8BEA0RHRIpEzkUSRVVFmkXeRiJGZ0arRvBHNUd7R8BIBUhLSJFI10kdSWNJqUnwSj␍
dKfUrESwxLU0uaS+JMKkxyTLpNAk1KTZNN3E4lTm5Ot08AT0lPk0/dUCdQcVC7UQZRUFGbUeZS␍
MVJ8UsdTE1NfU6pT9lRCVI9U21UoVXVVwlYPVlxWqVb3V0RXklfgWC9YfVjLWRpZaVm4WgdaVl␍
qmWvVbRVuVW+VcNVyGXNZdJ114XcleGl5sXr1fD19hX7NgBWBXYKpg/GFPYaJh9WJJYpxi8GND␍
Y5dj62RAZJRk6WU9ZZJl52Y9ZpJm6Gc9Z5Nn6Wg/aJZo7GlDaZpp8WpIap9q92tPa6dr/2xXbK␍
9tCG1gbbluEm5rbsRvHm94b9FwK3CGcOBxOnGVcfByS3KmcwFzXXO4dBR0cHTMdSh1hXXhdj52␍
m3b4d1Z3s3gReG54zHkqeYl553pGeqV7BHtje8J8IXyBfOF9QX2hfgF+Yn7CfyN/hH/lgEeAqI␍
EKgWuBzYIwgpKC9INXg7qEHYSAhOOFR4Wrhg6GcobXhzuHn4gEiGmIzokziZmJ/opkisqLMIuW␍
i/yMY4zKjTGNmI3/jmaOzo82j56QBpBukNaRP5GokhGSepLjk02TtpQglIqU9JVflcmWNJaflw␍
qXdZfgmEyYuJkkmZCZ/JpomtWbQpuvnByciZz3nWSd0p5Anq6fHZ+Ln/qgaaDYoUehtqImopaj␍
BqN2o+akVqTHpTilqaYapoum/adup+CoUqjEqTepqaocqo+rAqt1q+msXKzQrUStuK4trqGvFq␍
+LsACwdbDqsWCx1rJLssKzOLOutCW0nLUTtYq2AbZ5tvC3aLfguFm40blKucK6O7q1uy67p7wh␍
vJu9Fb2Pvgq+hL7/v3q/9cBwwOzBZ8Hjwl/C28NYw9TEUcTOxUvFyMZGxsPHQce/yD3IvMk6yb␍
nKOMq3yzbLtsw1zLXNNc21zjbOts83z7jQOdC60TzRvtI/0sHTRNPG1EnUy9VO1dHWVdbY11zX␍
4Nhk2OjZbNnx2nba+9uA3AXcit0Q3ZbeHN6i3ynfr+A24L3hROHM4lPi2+Nj4+vkc+T85YTmDe␍
aW5x/nqegy6LzpRunQ6lvq5etw6/vshu0R7ZzuKO6070DvzPBY8OXxcvH/8ozzGfOn9DT0wvVQ␍
9d72bfb794r4Gfio+Tj5x/pX+uf7d/wH/Jj9Kf26/kv+3P9t////4QBMRXhpZgAATU0AKgAAAA␍
gAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAMqADAAQAAAABAAAA␍
MgAAAAD/2wBDAAIBAQIBAQICAQICAgICAwUDAwMDAwYEBAMFBwYHBwcGBgYHCAsJBwgKCAYGCQ␍
0JCgsLDAwMBwkNDg0MDgsMDAv/2wBDAQICAgMCAwUDAwULCAYICwsLCwsLCwsLCwsLCwsLCwsL␍
CwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwv/wAARCAAyADIDASIAAhEBAxEB/8QAHw␍
AAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQR␍
BRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRk␍
dISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKz␍
tLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQ␍
EBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJB␍
UQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1␍
RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3␍
uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9/K␍
4L9oT9oLR/2efBo1PxGr3V3csYrGyjYCS6kAyeT91RwWbnGRwSQD1eqeMtI0PVbax1rVNOs769␍
IFvbz3KRyz5OBsQnLcgjgV8u/tsfBi9+LXxcink8a+B9GtdPsUggstV1XyJ4ySXdzHsON2V5zy␍
FFfHca53i8qyurUyqKniLqK1Xut9Wm7aLVJ7u2ljKtNxi+Xc8u+Inxa+K/gvwnpeqw3UvhPwx4␍
qnm1HS7XTpk2xhyHZQeZFU7t4UkD5jgDoM34S/HL4weNvGVtonw88Vaxfanfq6xxXU6SJgKWYk␍
zAhcAE56+nart7+y3qmpWFpa6l8U/hvcWtgCltDL4id47cNyRGpTCg98Ypuk/sq6joGoxXuhfF␍
H4a2V5Ad0U9v4haKWM9PlZUBHUjj1r+Y54fiGWMp1YyrqkuW6VeKlZJc6i01GKvflXLaKsraHm␍
2qXvrb1Po39jv9o2y15T8PfFGm2/h/xJ4eD2ywRybor3y2IkZSST5m4MzAk7slgTzj3+vgj4e/␍
s36j4O+JOj67afEr4aSXljqEdySmvFpZjvG5clPmLgsvPXdX27rPxG8P+HdftdK1/W9JstTvsf␍
Z7Se7SOabPA2oTk5PA9e1f0D4c55ja+Wyo5vFQdJqMW3H3ov4E+XTmVraJX00vc78PNuNpm1RR␍
RX6YdB+cX7dF5NP+1B4oaaV2a3MCxEtzEBBGQF9MEk/U079tO5k1D4yWs967SzTaDp0ju3JZjD␍
kk/U1D+3Ef+MnvF3+/D/6Tx0/9sf8A5K3Yf9i9pv8A6Ir+JeIpN1M8Tf8AzEx/9Krnjz+36/5n␍
lG0ego2D0H5UtFfntjnLnhtAfEumcD/j8h7f9NFrv/2zLuWf9pzxi8sjs8V0io27lAsMe0A9sd␍
q4Hw1/yMum/wDX3D/6MWu+/bR/5Oc8af8AXzH/AOk8VfRUdMgxH/X6l/6brmi/hv1X6n6PaDM1␍
xoVlJMxZ3gRmJ6klRk0U3w3n/hHbD/r2j/8AQRRX960XenH0R7iPNfin+xn4J+L/AI/TxH4sgv␍
1vSEFxHb3Hlw3oTgeauCc4AXKkZAr5O/4KDwJbftLXkcCKkcem2iqqjAUBCAAK/QiuH+LvwN8I␍
/Eq3m1HxzoGn6lf2dq6wzyofMUAEgZBGQCSQDnGa/N+OuAKOe5dWpZbGFKrOcak5NW53FS3aTd␍
/eb23v3bOetQU4tR0Z+YdFdz+zJ4YsPGvx68K6V4ptY73T767KTwSZ2yqI3bBxz1Ar03/goJ8I␍
fDfwk8ReGIfhxpFtpMV7bXDzrCG/eFWjCkkk9AT+Z9a/lTC8MYjF5JiM9jOPsqU1BrXmbfLqtL␍
W95de55apNwc+x4N4a/wCRl03P/P3D/wCjFr9GPiJ+yB4G+KXxCj8S+LtPnk1DKGdI7hkhvNgA␍
XzUHXgAcYyAAc15l+wd8C/CHib4OaT4k8QaBYXuuQ307JdzKXZSknyHBOOMDHHGK+nK/ofws4C␍
pUMqlXzOMKtPEezqRi1flspNN3Vr+9bS/XV3PQw1C0Ly1vqIqhVAUAAcADtRS0V+4nYFVtYUNp␍
N0GAIMLgg9/lNFFZ1vgl6MD82/2POP2mvBX/AF+t/wCiZK9o/wCCpqKNd8FMANxgvATjkgNBj+␍
Z/Oiiv5EyP/k3eZ/8AX6H50jyof7vL1/yPWf8AgnuAP2YNJI6m6u8+/wC/evbKKK/pbgf/AJJ7␍
L/8ArzT/APSUejR/hx9Aooor6k0P/9k=␍
END:VCARD␍
@@ -0,0 +1,5 @@
BEGIN:VCARD
VERSION:3.0
FN;CHARSET=SHIFT_JIS:ˆÉ”\ Œ\ˆê ˆÉ—\
N;CHARSET=SHIFT_JIS:ˆÉ”\;Œ\ˆê;ˆÉ—\;;
END:VCARD
@@ -0,0 +1,5 @@
BEGIN:VCARD
VERSION:3.0
N:F;G;M;;
TEL;TYPE="费":1
END:VCARD
@@ -0,0 +1,5 @@
BEGIN:VCARD
VERSION:3.0
N:F;G;M;;
TEL;TYPE=PAGER,WORK,MSG:6101231234@pagersample.com
END:VCARD
@@ -0,0 +1,6 @@
BEGIN:VCARD
VERSION:3.0
FN:Pause Wait
N:Pause;Wait;;;
TEL:p1234p5678w9
END:VCARD
@@ -0,0 +1,13 @@
BEGIN:VCARD
VERSION:3.0
FN:And Roid
N:And;Roid;;;
ORG:Open;Handset; Alliance
SORT-STRING:android
TEL;TYPE=PREF;TYPE=VOICE:0300000000
CLASS:PUBLIC
X-GNO:0
X-GN:group0
X-REDUCTION:0
REV:20081031T065854Z
END:VCARD
+5
View File
@@ -0,0 +1,5 @@
BEGIN:VCARD
VERSION:3.0
FN:Android
IMPP;TYPE=personal:sip:android@android.example.com
END:VCARD
+7
View File
@@ -0,0 +1,7 @@
BEGIN:VCARD
VERSION:4.0
FN:安藤 ロイド
N:安藤;ロイド;;;
TEL;TYPE=HOME:tel:1
TEL;TYPE=HOME:sip:example@example.com
END:VCARD
@@ -0,0 +1,6 @@
BEGIN:VCARD
VERSION:4.0
FN:安藤 ロイド
N;SORT-AS="あんどう;ろいど":安藤;ロイド;;;
ORG;TYPE=WORK;SORT-AS="ぐーぐる;けんさくぶもん":グーグル;検索部門
END:VCARD
@@ -0,0 +1,31 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard;
import com.android.vcard.JapaneseUtils;
import junit.framework.TestCase;
public class JapaneseUtilsTest extends TestCase {
static final char TEST_CONTAINED_CHAR = '\uFFE5';
static final char TEST_UNCONTAINED_CHAR = '\uFFF5';
public void testTryGetHalfWidthText() {
assertNull(JapaneseUtils.tryGetHalfWidthText(TEST_UNCONTAINED_CHAR));
assertEquals(JapaneseUtils.tryGetHalfWidthText(TEST_CONTAINED_CHAR), "\u005C\u005C");
}
}
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.vcard.tests;
import android.content.ContentValues;
import android.provider.ContactsContract;
import com.android.vcard.VCardBuilder;
import com.android.vcard.VCardConfig;
import com.google.android.collect.Lists;
import junit.framework.TestCase;
import java.util.ArrayList;
/**
* Unit test for VCardBuilder.
*/
public class VCardBuilderTest extends TestCase {
public void testVCardNameFieldFromDisplayName() {
final ArrayList<ContentValues> contentList = Lists.newArrayList();
final ContentValues values = new ContentValues();
values.put(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, "ने");
contentList.add(values);
final VCardBuilder builder = new VCardBuilder(VCardConfig.VCARD_TYPE_DEFAULT);
builder.appendNameProperties(contentList);
final String actual = builder.toString();
final String expectedCommon = ";CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:" +
"=E0=A4=A8=E0=A5=87";
final String expectedName = "N" + expectedCommon + ";;;;";
final String expectedFullName = "FN" + expectedCommon;
assertTrue("Actual value:\n" + actual + " expected to contain\n" + expectedName +
"\nbut does not.", actual.contains(expectedName));
assertTrue("Actual value:\n" + actual + " expected to contain\n" + expectedFullName +
"\nbut does not.", actual.contains(expectedFullName));
}
}
@@ -0,0 +1,436 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests;
import com.android.vcard.VCardConfig;
import com.android.vcard.VCardConstants;
import com.android.vcard.VCardEntry;
import com.android.vcard.VCardEntry.AndroidCustomData;
import com.android.vcard.VCardEntry.AnniversaryData;
import com.android.vcard.VCardEntry.BirthdayData;
import com.android.vcard.VCardEntry.EmailData;
import com.android.vcard.VCardEntry.EntryElement;
import com.android.vcard.VCardEntry.EntryLabel;
import com.android.vcard.VCardEntry.ImData;
import com.android.vcard.VCardEntry.NameData;
import com.android.vcard.VCardEntry.NicknameData;
import com.android.vcard.VCardEntry.NoteData;
import com.android.vcard.VCardEntry.OrganizationData;
import com.android.vcard.VCardEntry.PhoneData;
import com.android.vcard.VCardEntry.PhotoData;
import com.android.vcard.VCardEntry.PostalData;
import com.android.vcard.VCardEntry.SipData;
import com.android.vcard.VCardEntryConstructor;
import com.android.vcard.VCardEntryHandler;
import com.android.vcard.VCardInterpreter;
import com.android.vcard.VCardProperty;
import android.accounts.Account;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Im;
import android.provider.ContactsContract.CommonDataKinds.Organization;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.CommonDataKinds.SipAddress;
import android.test.AndroidTestCase;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class VCardEntryTests extends AndroidTestCase {
private class MockVCardEntryHandler implements VCardEntryHandler {
private List<VCardEntry> mEntries = new ArrayList<VCardEntry>();
private boolean mOnStartCalled;
private boolean mOnEndCalled;
@Override
public void onStart() {
assertFalse(mOnStartCalled);
mOnStartCalled = true;
}
@Override
public void onEntryCreated(VCardEntry entry) {
assertTrue(mOnStartCalled);
assertFalse(mOnEndCalled);
mEntries.add(entry);
}
@Override
public void onEnd() {
assertTrue(mOnStartCalled);
assertFalse(mOnEndCalled);
mOnEndCalled = true;
}
public List<VCardEntry> getEntries() {
return mEntries;
}
}
/**
* Tests VCardEntry and related clasess can handle nested classes given
* {@link VCardInterpreter} is called appropriately.
*
* This test manually calls VCardInterpreter's callback mechanism and checks
* {@link VCardEntryConstructor} constructs {@link VCardEntry} per given calls.
*
* Intended vCard is as follows:
* <code>
* BEGIN:VCARD
* N:test1
* BEGIN:VCARD
* N:test2
* END:VCARD
* TEL:1
* END:VCARD
* </code>
*/
public void testNestHandling() {
VCardEntryConstructor entryConstructor = new VCardEntryConstructor();
MockVCardEntryHandler entryHandler = new MockVCardEntryHandler();
entryConstructor.addEntryHandler(entryHandler);
entryConstructor.onVCardStarted();
entryConstructor.onEntryStarted();
VCardProperty property = new VCardProperty();
property.setName(VCardConstants.PROPERTY_N);
property.setValues("test1");
entryConstructor.onPropertyCreated(property);
entryConstructor.onEntryStarted(); // begin nest
property = new VCardProperty();
property.setName(VCardConstants.PROPERTY_N);
property.setValues("test2");
entryConstructor.onPropertyCreated(property);
entryConstructor.onEntryEnded(); // end nest
property = new VCardProperty();
property.setName(VCardConstants.PROPERTY_TEL);
property.setValues("1");
entryConstructor.onPropertyCreated(property);
entryConstructor.onEntryEnded();
entryConstructor.onVCardEnded();
List<VCardEntry> entries = entryHandler.getEntries();
assertEquals(2, entries.size());
VCardEntry parent = entries.get(1);
VCardEntry child = entries.get(0);
assertEquals("test1", parent.getDisplayName());
assertEquals("test2", child.getDisplayName());
List<VCardEntry.PhoneData> phoneList = parent.getPhoneList();
assertNotNull(phoneList);
assertEquals(1, phoneList.size());
assertEquals("1", phoneList.get(0).getNumber());
}
private class MockEntryElementIterator implements VCardEntry.EntryElementIterator {
private boolean mStartCalled;
private boolean mEndCalled;
private EntryLabel mLabel;
private final Map<EntryLabel, EntryElement> mExpectedElements =
new HashMap<EntryLabel, EntryElement>();
public void addExpectedElement(EntryElement elem) {
mExpectedElements.put(elem.getEntryLabel(), elem);
}
@Override
public void onIterationStarted() {
assertFalse(mStartCalled);
assertFalse(mEndCalled);
assertNull(mLabel);
mStartCalled = true;
}
@Override
public void onIterationEnded() {
assertTrue(mStartCalled);
assertFalse(mEndCalled);
assertNull(mLabel);
assertTrue("Expected Elements remaining: " +
Arrays.toString(mExpectedElements.values().toArray()),
mExpectedElements.isEmpty());
}
@Override
public void onElementGroupStarted(EntryLabel label) {
assertTrue(mStartCalled);
assertFalse(mEndCalled);
assertNull(mLabel);
mLabel = label;
}
@Override
public void onElementGroupEnded() {
assertTrue(mStartCalled);
assertFalse(mEndCalled);
assertNotNull(mLabel);
mLabel = null;
}
@Override
public boolean onElement(EntryElement elem) {
EntryElement expectedElem = mExpectedElements.remove(elem.getEntryLabel());
assertNotNull("Unexpected elem: " + elem.toString(), expectedElem);
assertEquals(expectedElem, elem);
return true;
}
}
/**
* Tests every element in VCardEntry is iterated by
* {@link VCardEntry#iterateAllData(com.android.vcard.VCardEntry.EntryElementIterator)}.
*/
public void testEntryElementIterator() {
VCardEntry entry = new VCardEntry();
MockEntryElementIterator iterator = new MockEntryElementIterator();
VCardProperty property = new VCardProperty();
property.setName("N");
property.setValues("family", "given", "middle", "prefix", "suffix");
entry.addProperty(property);
NameData nameData = new NameData();
nameData.setFamily("family");
nameData.setGiven("given");
nameData.setMiddle("middle");
nameData.setPrefix("prefix");
nameData.setSuffix("suffix");
iterator.addExpectedElement(nameData);
property = new VCardProperty();
property.setName("TEL");
property.setParameter("TYPE", "HOME");
property.setValues("1");
entry.addProperty(property);
PhoneData phoneData = new PhoneData("1", Phone.TYPE_HOME, null, false);
iterator.addExpectedElement(phoneData);
property = new VCardProperty();
property.setName("EMAIL");
property.setParameter("TYPE", "WORK");
property.setValues("email");
entry.addProperty(property);
EmailData emailData = new EmailData("email", Email.TYPE_WORK, null, false);
iterator.addExpectedElement(emailData);
property = new VCardProperty();
property.setName("ADR");
property.setParameter("TYPE", "HOME");
property.setValues(null, null, "street");
entry.addProperty(property);
PostalData postalData = new PostalData(null, null, "street", null, null, null,
null, StructuredPostal.TYPE_HOME, null, false,
VCardConfig.VCARD_TYPE_DEFAULT);
iterator.addExpectedElement(postalData);
property = new VCardProperty();
property.setName("ORG");
property.setValues("organization", "depertment");
entry.addProperty(property);
OrganizationData organizationData = new OrganizationData(
"organization", "depertment", null, null, Organization.TYPE_WORK, false);
iterator.addExpectedElement(organizationData);
property = new VCardProperty();
property.setName("X-GOOGLE-TALK");
property.setParameter("TYPE", "WORK");
property.setValues("googletalk");
entry.addProperty(property);
ImData imData = new ImData(
Im.PROTOCOL_GOOGLE_TALK, null, "googletalk", Im.TYPE_WORK, false);
iterator.addExpectedElement(imData);
property = new VCardProperty();
property.setName("PHOTO");
property.setParameter("TYPE", "PNG");
byte[] photoBytes = new byte[] {1};
property.setByteValue(photoBytes);
entry.addProperty(property);
PhotoData photoData = new PhotoData("PNG", photoBytes, false);
iterator.addExpectedElement(photoData);
property = new VCardProperty();
property.setName("X-SIP");
property.setValues("sipdata");
entry.addProperty(property);
SipData sipData = new SipData("sip:sipdata", SipAddress.TYPE_OTHER, null, false);
iterator.addExpectedElement(sipData);
property = new VCardProperty();
property.setName("NICKNAME");
property.setValues("nickname");
entry.addProperty(property);
NicknameData nicknameData = new NicknameData("nickname");
iterator.addExpectedElement(nicknameData);
property = new VCardProperty();
property.setName("NOTE");
property.setValues("note");
entry.addProperty(property);
NoteData noteData = new NoteData("note");
iterator.addExpectedElement(noteData);
property = new VCardProperty();
property.setName("BDAY");
property.setValues("birthday");
entry.addProperty(property);
BirthdayData birthdayData = new BirthdayData("birthday");
iterator.addExpectedElement(birthdayData);
property = new VCardProperty();
property.setName("ANNIVERSARY");
property.setValues("anniversary");
entry.addProperty(property);
AnniversaryData anniversaryData = new AnniversaryData("anniversary");
iterator.addExpectedElement(anniversaryData);
property = new VCardProperty();
property.setName("X-ANDROID-CUSTOM");
property.setValues("mime;value");
entry.addProperty(property);
AndroidCustomData androidCustom = new AndroidCustomData("mime", Arrays.asList("value"));
iterator.addExpectedElement(androidCustom);
entry.iterateAllData(iterator);
}
public void testToString() {
VCardEntry entry = new VCardEntry();
VCardProperty property = new VCardProperty();
property.setName("N");
property.setValues("Family", "Given", "Middle", "Prefix", "Suffix");
entry.addProperty(property);
entry.consolidateFields();
String result = entry.toString();
assertNotNull(result);
assertTrue(result.contains(String.valueOf(entry.hashCode())));
assertTrue(result.contains(VCardEntry.EntryLabel.NAME.toString()));
assertTrue(result.contains("Family"));
assertTrue(result.contains("Given"));
assertTrue(result.contains("Middle"));
assertTrue(result.contains("Prefix"));
assertTrue(result.contains("Suffix"));
}
/**
* Tests that VCardEntry emits correct insert operation for name field.
*/
public void testConstructInsertOperationsInsertName() {
VCardEntry entry = new VCardEntry();
VCardProperty property = new VCardProperty();
property.setName("N");
property.setValues("Family", "Given", "Middle", "Prefix", "Suffix");
entry.addProperty(property);
entry.consolidateFields();
NameData nameData = entry.getNameData();
assertEquals("Family", nameData.getFamily());
assertEquals("Given", nameData.getGiven());
assertEquals("Middle", nameData.getMiddle());
assertEquals("Prefix", nameData.getPrefix());
assertEquals("Suffix", nameData.getSuffix());
ContentResolver resolver = getContext().getContentResolver();
ArrayList<ContentProviderOperation> operationList =
new ArrayList<ContentProviderOperation>();
entry.constructInsertOperations(resolver, operationList);
// Need too many details for testing these. Just check basics.
// TODO: introduce nice-to-test mechanism here.
assertEquals(2, operationList.size());
assertEquals(ContentProviderOperation.TYPE_INSERT, operationList.get(0).getType());
assertEquals(ContentProviderOperation.TYPE_INSERT, operationList.get(1).getType());
}
/**
* Tests that VCardEntry refrains from emitting unnecessary insert operation.
*/
public void testConstructInsertOperationsEmptyData() {
VCardEntry entry = new VCardEntry();
ContentResolver resolver = getContext().getContentResolver();
ArrayList<ContentProviderOperation> operationList =
new ArrayList<ContentProviderOperation>();
entry.constructInsertOperations(resolver, operationList);
assertEquals(0, operationList.size());
}
/**
* Tests that VCardEntry can add an account via the constructor
*/
public void testConstructor_withAccount_canGetAccount() {
Account account = new Account("test-type", "test-name");
VCardEntry entry = new VCardEntry(VCardConfig.VCARD_TYPE_V21_GENERIC, account);
assertEquals(entry.getAccount(), account);
}
/**
* Tests that VCardEntry can add a null account via the constructor
*/
public void testConstructor_withNullAccount_canGetNullAccount() {
VCardEntry entry = new VCardEntry(VCardConfig.VCARD_TYPE_V21_GENERIC, null);
assertEquals(entry.getAccount(), null);
}
/**
* Tests that VCardEntry can add an account via the setter, updating a null account to a value
*/
public void testSetAccount_fromNullToValue_canGetAccount() {
Account account = new Account("test-type", "test-name");
VCardEntry entry = new VCardEntry();
assertEquals(entry.getAccount(), null);
entry.setAccount(account);
assertEquals(entry.getAccount(), account);
}
/**
* Tests that VCardEntry can add an account via the setter, changing one account to another
*/
public void testSetAccount_fromToNewValue_canGetAccount() {
Account account1 = new Account("test-type-1", "test-name-1");
VCardEntry entry = new VCardEntry(VCardConfig.VCARD_TYPE_V21_GENERIC, account1);
assertEquals(entry.getAccount(), account1);
Account account2 = new Account("test-type-2", "test-name-2");
entry.setAccount(account2);
assertEquals(entry.getAccount(), account2);
}
/**
* Tests that VCardEntry can add an account via the setter, changing one account to another
*/
public void testSetAccount_setValueTwice_canGetAccount() {
VCardEntry entry = new VCardEntry();
assertEquals(entry.getAccount(), null);
Account account1 = new Account("test-type-1", "test-name-1");
entry.setAccount(account1);
assertEquals(entry.getAccount(), account1);
Account account2 = new Account("test-type-2", "test-name-2");
entry.setAccount(account2);
assertEquals(entry.getAccount(), account2);
}
// TODO: add bunch of test for constructInsertOperations..
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests;
import com.android.vcard.tests.testutils.VCardTestsBase;
/**
* Test cases specific for nested vCard.
*/
public class VCardImporterNestTests extends VCardTestsBase {
public void testSimpleNest() {
mVerifier.initForImportTest(V21, R.raw.v21_nest);
mVerifier.addPropertyNodesVerifierElem()
.addExpectedNodeWithOrder("N", "nest1");
mVerifier.addPropertyNodesVerifierElem()
.addExpectedNodeWithOrder("N", "nest2");
// Parent comes last.
mVerifier.addPropertyNodesVerifierElem()
.addExpectedNodeWithOrder("N", "parent")
.addExpectedNodeWithOrder("TEL", "1");
}
public void testSimpleNestWithMime() {
mVerifier.initForImportTest(V21, R.raw.v21_nest_with_mime);
mVerifier.addPropertyNodesVerifierElem()
.addExpectedNodeWithOrder("N", "nest1");
mVerifier.addPropertyNodesVerifierElem()
.addExpectedNodeWithOrder("N", "nest2");
// Parent comes last.
mVerifier.addPropertyNodesVerifierElem()
.addExpectedNodeWithOrder("N", "parent")
.addExpectedNodeWithOrder("TEL", "1");
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,440 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests;
import android.content.ContentValues;
import android.provider.ContactsContract.CommonDataKinds.Nickname;
import android.provider.ContactsContract.CommonDataKinds.Note;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import com.android.vcard.VCardConfig;
import com.android.vcard.VCardConstants;
import com.android.vcard.tests.testutils.ContactEntry;
import com.android.vcard.tests.testutils.ContentValuesBuilder;
import com.android.vcard.tests.testutils.PropertyNodesVerifierElem;
import com.android.vcard.tests.testutils.VCardTestsBase;
import com.android.vcard.tests.testutils.PropertyNodesVerifierElem.TypeSet;
import java.util.Arrays;
public class VCardJapanizationTests extends VCardTestsBase {
private void testNameUtf8Common(int vcardType) {
mVerifier.initForExportTest(vcardType);
ContactEntry entry = mVerifier.addInputEntry();
entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
.put(StructuredName.FAMILY_NAME, "\u3075\u308B\u3069")
.put(StructuredName.GIVEN_NAME, "\u3091\u308A\u304B")
.put(StructuredName.MIDDLE_NAME, "B")
.put(StructuredName.PREFIX, "Dr.")
.put(StructuredName.SUFFIX, "Ph.D");
ContentValues contentValues =
(VCardConfig.isVersion21(vcardType) ? mContentValuesForQPAndUtf8 : null);
mVerifier.addPropertyNodesVerifierElem()
.addExpectedNode("FN", "Dr. \u3075\u308B\u3069 B \u3091\u308A\u304B Ph.D",
contentValues)
.addExpectedNode("N", "\u3075\u308B\u3069;\u3091\u308A\u304B;B;Dr.;Ph.D",
Arrays.asList(
"\u3075\u308B\u3069", "\u3091\u308A\u304B", "B", "Dr.", "Ph.D"),
null, contentValues, null, null);
}
public void testNameUtf8V21() {
testNameUtf8Common(VCardConfig.VCARD_TYPE_V21_JAPANESE);
}
public void testNameUtf8V30() {
testNameUtf8Common(VCardConfig.VCARD_TYPE_V30_JAPANESE);
}
public void testNameShiftJis() {
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V30_JAPANESE, "Shift_JIS");
ContactEntry entry = mVerifier.addInputEntry();
entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
.put(StructuredName.FAMILY_NAME, "\u3075\u308B\u3069")
.put(StructuredName.GIVEN_NAME, "\u3091\u308A\u304B")
.put(StructuredName.MIDDLE_NAME, "B")
.put(StructuredName.PREFIX, "Dr.")
.put(StructuredName.SUFFIX, "Ph.D");
mVerifier.addPropertyNodesVerifierElem()
.addExpectedNode("FN", "Dr. \u3075\u308B\u3069 B \u3091\u308A\u304B Ph.D",
mContentValuesForSJis)
.addExpectedNode("N", "\u3075\u308B\u3069;\u3091\u308A\u304B;B;Dr.;Ph.D",
Arrays.asList(
"\u3075\u308B\u3069", "\u3091\u308A\u304B", "B", "Dr.", "Ph.D"),
null, mContentValuesForSJis, null, null);
}
/**
* DoCoMo phones require all name elements should be in "family name" field.
*/
public void testNameDoCoMo() {
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
ContactEntry entry = mVerifier.addInputEntry();
entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
.put(StructuredName.FAMILY_NAME, "\u3075\u308B\u3069")
.put(StructuredName.GIVEN_NAME, "\u3091\u308A\u304B")
.put(StructuredName.MIDDLE_NAME, "B")
.put(StructuredName.PREFIX, "Dr.")
.put(StructuredName.SUFFIX, "Ph.D");
final String fullName = "Dr. \u3075\u308B\u3069 B \u3091\u308A\u304B Ph.D";
mVerifier.addPropertyNodesVerifierElem()
.addExpectedNode("N", fullName + ";;;;",
Arrays.asList(fullName, "", "", "", ""),
null, mContentValuesForSJis, null, null)
.addExpectedNode("FN", fullName, mContentValuesForSJis)
.addExpectedNode("SOUND", ";;;;", new TypeSet("X-IRMC-N"))
.addExpectedNode("TEL", "", new TypeSet("HOME"))
.addExpectedNode("EMAIL", "", new TypeSet("HOME"))
.addExpectedNode("ADR", "", new TypeSet("HOME"))
.addExpectedNode("X-CLASS", "PUBLIC")
.addExpectedNode("X-REDUCTION", "")
.addExpectedNode("X-NO", "")
.addExpectedNode("X-DCM-HMN-MODE", "");
}
private void testPhoneticNameCommon(int vcardType, String charset) {
mVerifier.initForExportTest(vcardType, charset);
ContactEntry entry = mVerifier.addInputEntry();
entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
.put(StructuredName.PHONETIC_FAMILY_NAME, "\u3084\u307E\u3060")
.put(StructuredName.PHONETIC_MIDDLE_NAME, "\u30DF\u30C9\u30EB\u30CD\u30FC\u30E0")
.put(StructuredName.PHONETIC_GIVEN_NAME, "\u305F\u308D\u3046");
final ContentValues contentValues =
("SHIFT_JIS".equalsIgnoreCase(charset) ?
(VCardConfig.isVersion21(vcardType) ? mContentValuesForQPAndSJis :
mContentValuesForSJis) :
(VCardConfig.isVersion21(vcardType) ? mContentValuesForQPAndUtf8 : null));
PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElemWithEmptyName();
elem.addExpectedNode("X-PHONETIC-LAST-NAME", "\u3084\u307E\u3060",
contentValues)
.addExpectedNode("X-PHONETIC-MIDDLE-NAME",
"\u30DF\u30C9\u30EB\u30CD\u30FC\u30E0",
contentValues)
.addExpectedNode("X-PHONETIC-FIRST-NAME", "\u305F\u308D\u3046",
contentValues);
if (!VCardConfig.isVersion21(vcardType)) {
elem.addExpectedNode("SORT-STRING",
"\u3084\u307E\u3060 \u30DF\u30C9\u30EB\u30CD\u30FC\u30E0 \u305F\u308D\u3046",
contentValues);
}
ContentValuesBuilder builder = mVerifier.addContentValuesVerifierElem()
.addExpected(StructuredName.CONTENT_ITEM_TYPE);
builder.put(StructuredName.PHONETIC_FAMILY_NAME, "\u3084\u307E\u3060")
.put(StructuredName.PHONETIC_MIDDLE_NAME, "\u30DF\u30C9\u30EB\u30CD\u30FC\u30E0")
.put(StructuredName.PHONETIC_GIVEN_NAME, "\u305F\u308D\u3046")
.put(StructuredName.DISPLAY_NAME,
"\u3084\u307E\u3060 \u30DF\u30C9\u30EB\u30CD\u30FC\u30E0 " +
"\u305F\u308D\u3046");
}
public void testPhoneticNameForJapaneseV21Utf8() {
testPhoneticNameCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE, null);
}
public void testPhoneticNameForJapaneseV21Sjis() {
testPhoneticNameCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE, "Shift_JIS");
}
public void testPhoneticNameForJapaneseV30Utf8() {
testPhoneticNameCommon(VCardConfig.VCARD_TYPE_V30_JAPANESE, null);
}
public void testPhoneticNameForJapaneseV30SJis() {
testPhoneticNameCommon(VCardConfig.VCARD_TYPE_V30_JAPANESE, "Shift_JIS");
}
public void testPhoneticNameForMobileV21_1() {
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE_MOBILE, "Shift_JIS");
ContactEntry entry = mVerifier.addInputEntry();
entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
.put(StructuredName.PHONETIC_FAMILY_NAME, "\u3084\u307E\u3060")
.put(StructuredName.PHONETIC_MIDDLE_NAME, "\u30DF\u30C9\u30EB\u30CD\u30FC\u30E0")
.put(StructuredName.PHONETIC_GIVEN_NAME, "\u305F\u308D\u3046");
mVerifier.addPropertyNodesVerifierElem()
.addExpectedNode("SOUND",
"\uFF94\uFF8F\uFF80\uFF9E \uFF90\uFF84\uFF9E\uFF99\uFF88\uFF70\uFF91 " +
"\uFF80\uFF9B\uFF73;;;;",
mContentValuesForSJis, new TypeSet("X-IRMC-N"));
ContentValuesBuilder builder = mVerifier.addContentValuesVerifierElem()
.addExpected(StructuredName.CONTENT_ITEM_TYPE);
builder.put(StructuredName.PHONETIC_FAMILY_NAME, "\uFF94\uFF8F\uFF80\uFF9E")
.put(StructuredName.PHONETIC_MIDDLE_NAME,
"\uFF90\uFF84\uFF9E\uFF99\uFF88\uFF70\uFF91")
.put(StructuredName.PHONETIC_GIVEN_NAME, "\uFF80\uFF9B\uFF73")
.put(StructuredName.DISPLAY_NAME,
"\uFF94\uFF8F\uFF80\uFF9E \uFF90\uFF84\uFF9E\uFF99\uFF88\uFF70\uFF91 " +
"\uFF80\uFF9B\uFF73");
}
public void testPhoneticNameForMobileV21_2() {
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE_MOBILE, "Shift_JIS");
ContactEntry entry = mVerifier.addInputEntry();
entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
.put(StructuredName.PHONETIC_FAMILY_NAME, "\u3084\u307E\u3060")
.put(StructuredName.PHONETIC_GIVEN_NAME, "\u305F\u308D\u3046");
mVerifier.addPropertyNodesVerifierElem()
.addExpectedNode("SOUND", "\uFF94\uFF8F\uFF80\uFF9E \uFF80\uFF9B\uFF73;;;;",
mContentValuesForSJis, new TypeSet("X-IRMC-N"));
ContentValuesBuilder builder = mVerifier.addContentValuesVerifierElem()
.addExpected(StructuredName.CONTENT_ITEM_TYPE);
builder.put(StructuredName.PHONETIC_FAMILY_NAME, "\uFF94\uFF8F\uFF80\uFF9E")
.put(StructuredName.PHONETIC_GIVEN_NAME, "\uFF80\uFF9B\uFF73")
.put(StructuredName.DISPLAY_NAME, "\uFF94\uFF8F\uFF80\uFF9E \uFF80\uFF9B\uFF73");
}
private void testPostalAddressWithJapaneseCommon(int vcardType, String charset) {
mVerifier.initForExportTest(vcardType, charset);
ContactEntry entry = mVerifier.addInputEntry();
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.POBOX, "\u79C1\u66F8\u7BB107")
.put(StructuredPostal.STREET, "\u96DB\u898B\u6CA2\u6751")
.put(StructuredPostal.CITY, "\u9E7F\u9AA8\u5E02")
.put(StructuredPostal.REGION, "\u00D7\u00D7\u770C")
.put(StructuredPostal.POSTCODE, "494-1313")
.put(StructuredPostal.COUNTRY, "\u65E5\u672C")
.put(StructuredPostal.FORMATTED_ADDRESS,
"\u3053\u3093\u306A\u3068\u3053\u308D\u3092\u898B"
+ "\u308B\u306A\u3093\u3066\u6687\u4EBA\u3067\u3059\u304B\uFF1F")
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
.put(StructuredPostal.LABEL, "\u304A\u3082\u3061\u304B\u3048\u308A");
ContentValues contentValues = ("UTF-8".equalsIgnoreCase(charset) ?
(VCardConfig.isVersion21(vcardType) ? mContentValuesForQPAndSJis :
mContentValuesForSJis) :
(VCardConfig.isVersion21(vcardType) ? mContentValuesForQPAndUtf8 :
mContentValuesForUtf8));
PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElemWithEmptyName();
// LABEL must be ignored in vCard 2.1. As for vCard 3.0, the current behavior is
// same as that in vCard 3.0, which can be changed in the future.
elem.addExpectedNode("ADR", Arrays.asList("\u79C1\u66F8\u7BB107",
"", "\u96DB\u898B\u6CA2\u6751", "\u9E7F\u9AA8\u5E02", "\u00D7\u00D7\u770C",
"494-1313", "\u65E5\u672C"),
contentValues);
mVerifier.addContentValuesVerifierElem().addExpected(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.POBOX, "\u79C1\u66F8\u7BB107")
.put(StructuredPostal.STREET, "\u96DB\u898B\u6CA2\u6751")
.put(StructuredPostal.CITY, "\u9E7F\u9AA8\u5E02")
.put(StructuredPostal.REGION, "\u00D7\u00D7\u770C")
.put(StructuredPostal.POSTCODE, "494-1313")
.put(StructuredPostal.COUNTRY, "\u65E5\u672C")
.put(StructuredPostal.FORMATTED_ADDRESS,
"\u65E5\u672C 494-1313 \u00D7\u00D7\u770C \u9E7F\u9AA8\u5E02 " +
"\u96DB\u898B\u6CA2\u6751 " + "\u79C1\u66F8\u7BB107")
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME);
}
public void testPostalAddresswithJapaneseV21() {
testPostalAddressWithJapaneseCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE, "Shift_JIS");
}
/**
* Verifies that only one address field is emitted toward DoCoMo phones.
* Prefered type must (should?) be: HOME > WORK > OTHER > CUSTOM
*/
public void testPostalAdrressForDoCoMo_1() {
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
ContactEntry entry = mVerifier.addInputEntry();
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
.put(StructuredPostal.POBOX, "1");
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
.put(StructuredPostal.POBOX, "2");
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME)
.put(StructuredPostal.POBOX, "3");
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
.put(StructuredPostal.LABEL, "custom")
.put(StructuredPostal.POBOX, "4");
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
.addExpectedNode("TEL", "", new TypeSet("HOME"))
.addExpectedNode("EMAIL", "", new TypeSet("HOME"))
.addExpectedNode("X-CLASS", "PUBLIC")
.addExpectedNode("X-REDUCTION", "")
.addExpectedNode("X-NO", "")
.addExpectedNode("X-DCM-HMN-MODE", "")
.addExpectedNode("ADR",
Arrays.asList("3", "", "", "", "", "", ""), new TypeSet("HOME"));
}
public void testPostalAdrressForDoCoMo_2() {
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
ContactEntry entry = mVerifier.addInputEntry();
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
.put(StructuredPostal.POBOX, "1");
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
.put(StructuredPostal.POBOX, "2");
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
.put(StructuredPostal.LABEL, "custom")
.put(StructuredPostal.POBOX, "3");
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
.addExpectedNode("TEL", "", new TypeSet("HOME"))
.addExpectedNode("EMAIL", "", new TypeSet("HOME"))
.addExpectedNode("X-CLASS", "PUBLIC")
.addExpectedNode("X-REDUCTION", "")
.addExpectedNode("X-NO", "")
.addExpectedNode("X-DCM-HMN-MODE", "")
.addExpectedNode("ADR",
Arrays.asList("2", "", "", "", "", "", ""), new TypeSet("WORK"));
}
public void testPostalAdrressForDoCoMo_3() {
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
ContactEntry entry = mVerifier.addInputEntry();
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
.put(StructuredPostal.LABEL, "custom1")
.put(StructuredPostal.POBOX, "1");
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
.put(StructuredPostal.POBOX, "2");
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_CUSTOM)
.put(StructuredPostal.LABEL, "custom2")
.put(StructuredPostal.POBOX, "3");
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
.addExpectedNode("TEL", "", new TypeSet("HOME"))
.addExpectedNode("EMAIL", "", new TypeSet("HOME"))
.addExpectedNode("X-CLASS", "PUBLIC")
.addExpectedNode("X-REDUCTION", "")
.addExpectedNode("X-NO", "")
.addExpectedNode("X-DCM-HMN-MODE", "")
.addExpectedNode("ADR",
Arrays.asList("2", "", "", "", "", "", ""),
new TypeSet("X-" + VCardConstants.PARAM_ADR_EXTRA_TYPE_OTHER));
}
/**
* Verifies the vCard exporter tolerates null TYPE.
*/
public void testPostalAdrressForDoCoMo_4() {
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
ContactEntry entry = mVerifier.addInputEntry();
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.POBOX, "1");
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_OTHER)
.put(StructuredPostal.POBOX, "2");
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME)
.put(StructuredPostal.POBOX, "3");
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
.put(StructuredPostal.POBOX, "4");
entry.addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
.put(StructuredPostal.POBOX, "5");
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
.addExpectedNode("TEL", "", new TypeSet("HOME"))
.addExpectedNode("EMAIL", "", new TypeSet("HOME"))
.addExpectedNode("X-CLASS", "PUBLIC")
.addExpectedNode("X-REDUCTION", "")
.addExpectedNode("X-NO", "")
.addExpectedNode("X-DCM-HMN-MODE", "")
.addExpectedNode("ADR",
Arrays.asList("3", "", "", "", "", "", ""), new TypeSet("HOME"));
}
private void testJapanesePhoneNumberCommon(int vcardType) {
mVerifier.initForExportTest(vcardType);
ContactEntry entry = mVerifier.addInputEntry();
entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
.put(Phone.NUMBER, "0312341234")
.put(Phone.TYPE, Phone.TYPE_HOME);
entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
.put(Phone.NUMBER, "09012341234")
.put(Phone.TYPE, Phone.TYPE_MOBILE);
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
.addExpectedNode("TEL", "03-1234-1234", new TypeSet("HOME"))
.addExpectedNode("TEL", "090-1234-1234", new TypeSet("CELL"));
}
public void testJapanesePhoneNumberV21_1() {
testJapanesePhoneNumberCommon(VCardConfig.VCARD_TYPE_V21_JAPANESE);
}
public void testJapanesePhoneNumberV30() {
testJapanesePhoneNumberCommon(VCardConfig.VCARD_TYPE_V30_JAPANESE);
}
public void testJapanesePhoneNumberDoCoMo() {
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
ContactEntry entry = mVerifier.addInputEntry();
entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
.put(Phone.NUMBER, "0312341234")
.put(Phone.TYPE, Phone.TYPE_HOME);
entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
.put(Phone.NUMBER, "09012341234")
.put(Phone.TYPE, Phone.TYPE_MOBILE);
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
.addExpectedNode("EMAIL", "", new TypeSet("HOME"))
.addExpectedNode("X-CLASS", "PUBLIC")
.addExpectedNode("X-REDUCTION", "")
.addExpectedNode("X-NO", "")
.addExpectedNode("X-DCM-HMN-MODE", "")
.addExpectedNode("ADR", "", new TypeSet("HOME"))
.addExpectedNode("TEL", "03-1234-1234", new TypeSet("HOME"))
.addExpectedNode("TEL", "090-1234-1234", new TypeSet("CELL"));
}
public void testNoteDoCoMo() {
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_DOCOMO, "Shift_JIS");
ContactEntry entry = mVerifier.addInputEntry();
entry.addContentValues(Note.CONTENT_ITEM_TYPE)
.put(Note.NOTE, "note1");
entry.addContentValues(Note.CONTENT_ITEM_TYPE)
.put(Note.NOTE, "note2");
entry.addContentValues(Note.CONTENT_ITEM_TYPE)
.put(Note.NOTE, "note3");
// More than one note fields must be aggregated into one note.
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
.addExpectedNode("TEL", "", new TypeSet("HOME"))
.addExpectedNode("EMAIL", "", new TypeSet("HOME"))
.addExpectedNode("X-CLASS", "PUBLIC")
.addExpectedNode("X-REDUCTION", "")
.addExpectedNode("X-NO", "")
.addExpectedNode("X-DCM-HMN-MODE", "")
.addExpectedNode("ADR", "", new TypeSet("HOME"))
.addExpectedNode("NOTE", "note1\nnote2\nnote3", mContentValuesForQP);
}
public void testAndroidCustomV21() {
mVerifier.initForExportTest(VCardConfig.VCARD_TYPE_V21_GENERIC);
mVerifier.addInputEntry().addContentValues(Nickname.CONTENT_ITEM_TYPE)
.put(Nickname.NAME, "\u304D\u3083\u30FC\u30A8\u30C3\u30C1\u30FC");
mVerifier.addPropertyNodesVerifierElemWithEmptyName()
.addExpectedNode("X-ANDROID-CUSTOM",
Arrays.asList(Nickname.CONTENT_ITEM_TYPE,
"\u304D\u3083\u30FC\u30A8\u30C3\u30C1\u30FC",
"", "", "", "", "", "", "", "", "", "", "", "", "", ""),
mContentValuesForQPAndUtf8);
}
}
@@ -0,0 +1,242 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests;
import com.android.vcard.VCardInterpreter;
import com.android.vcard.VCardParser;
import com.android.vcard.VCardParser_V21;
import com.android.vcard.VCardParser_V30;
import com.android.vcard.VCardProperty;
import com.android.vcard.exception.VCardException;
import android.test.AndroidTestCase;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Tests for basic {@link VCardParser} capability (e.g. if it calls callbacks
* in {@link VCardInterpreter}}.
*/
public class VCardParserTests extends AndroidTestCase {
private enum Order {
START,
END,
START_ENTRY,
END_ENTRY,
PROPERTY_CREATED,
}
private class MockVCardInterpreter implements VCardInterpreter {
private final List<Order> mHistory = new ArrayList<Order>();
private final List<Order> mExpectedOrder = new ArrayList<Order>();
public MockVCardInterpreter addExpectedOrder(Order order) {
mExpectedOrder.add(order);
return this;
}
private void inspectOrder(Order order) {
mHistory.add(order);
final Order top = mExpectedOrder.get(0);
assertEquals(top, order);
mExpectedOrder.remove(0);
}
public void verify() {
assertTrue(String.format("Remaining: " + Arrays.toString(mExpectedOrder.toArray())),
mExpectedOrder.isEmpty());
}
@Override
public void onVCardStarted() {
inspectOrder(Order.START);
}
@Override
public void onVCardEnded() {
inspectOrder(Order.END);
}
@Override
public void onEntryStarted() {
inspectOrder(Order.START_ENTRY);
}
@Override
public void onEntryEnded() {
inspectOrder(Order.END_ENTRY);
}
@Override
public void onPropertyCreated(VCardProperty property) {
inspectOrder(Order.PROPERTY_CREATED);
}
}
public void testSimple() throws IOException, VCardException {
InputStream inputStream = getContext().getResources().openRawResource(R.raw.v21_simple_1);
try {
VCardParser parser = new VCardParser_V21();
MockVCardInterpreter interpreter = new MockVCardInterpreter();
interpreter.addExpectedOrder(Order.START)
.addExpectedOrder(Order.START_ENTRY)
.addExpectedOrder(Order.PROPERTY_CREATED)
.addExpectedOrder(Order.END_ENTRY)
.addExpectedOrder(Order.END);
parser.addInterpreter(interpreter);
parser.parse(inputStream);
interpreter.verify();
} finally {
inputStream.close();
}
}
public void testNest() throws IOException, VCardException {
InputStream inputStream = getContext().getResources().openRawResource(R.raw.v21_nest);
try {
VCardParser parser = new VCardParser_V21();
MockVCardInterpreter interpreter = new MockVCardInterpreter();
interpreter.addExpectedOrder(Order.START)
.addExpectedOrder(Order.START_ENTRY)
.addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
.addExpectedOrder(Order.PROPERTY_CREATED) // For N
.addExpectedOrder(Order.START_ENTRY) // First nested vCard begins
.addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
.addExpectedOrder(Order.PROPERTY_CREATED) // For N
.addExpectedOrder(Order.END_ENTRY) // First nested vCard ends
.addExpectedOrder(Order.START_ENTRY) // Second nested vCard begins
.addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
.addExpectedOrder(Order.PROPERTY_CREATED) // For N
.addExpectedOrder(Order.END_ENTRY) // Second nested vCard ends
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.END_ENTRY)
.addExpectedOrder(Order.END);
parser.addInterpreter(interpreter);
parser.parse(inputStream);
interpreter.verify();
} finally {
inputStream.close();
}
}
/**
* Test vCard containing v3.0 line continuations and with non-standard
* line terminators \r\r\n coming from iOS 6.1.3. Tests to make sure the
* parser correctly skips the extra line terminators and still
* successfully concatenates the multi-line block.
*/
public void testIosMultiline() throws IOException, VCardException {
InputStream inputStream = getContext().getResources().openRawResource(R.raw.v30_ios_613_multiline);
try {
VCardParser parser = new VCardParser_V30();
MockVCardInterpreter interpreter = new MockVCardInterpreter();
interpreter.addExpectedOrder(Order.START)
.addExpectedOrder(Order.START_ENTRY)
.addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
.addExpectedOrder(Order.PROPERTY_CREATED) // For N
.addExpectedOrder(Order.PROPERTY_CREATED) // For FN
.addExpectedOrder(Order.PROPERTY_CREATED) // For ORG
.addExpectedOrder(Order.PROPERTY_CREATED) // For item1
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.PROPERTY_CREATED) // For item2
.addExpectedOrder(Order.PROPERTY_CREATED) // For item3
.addExpectedOrder(Order.PROPERTY_CREATED) // For PHOTO
.addExpectedOrder(Order.END_ENTRY)
.addExpectedOrder(Order.END);
parser.addInterpreter(interpreter);
parser.parse(inputStream);
interpreter.verify();
} finally {
inputStream.close();
}
}
/**
* Tests if {@link VCardParser#parse(InputStream)} parses the whole vCard file and
* {@link VCardParser#parseOne(InputStream)} parses just first entry of a vCard file
* with multiple vCard entries.
*/
public void testParseOne() throws IOException, VCardException {
InputStream inputStream =
getContext().getResources().openRawResource(R.raw.v21_multiple_entry);
try {
VCardParser parser = new VCardParser_V21();
MockVCardInterpreter interpreter = new MockVCardInterpreter();
interpreter.addExpectedOrder(Order.START)
.addExpectedOrder(Order.START_ENTRY)
.addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
.addExpectedOrder(Order.PROPERTY_CREATED) // For N
.addExpectedOrder(Order.PROPERTY_CREATED) // For SOUND
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.END_ENTRY)
.addExpectedOrder(Order.START_ENTRY)
.addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
.addExpectedOrder(Order.PROPERTY_CREATED) // For N
.addExpectedOrder(Order.PROPERTY_CREATED) // For SOUND
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.END_ENTRY)
.addExpectedOrder(Order.START_ENTRY)
.addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
.addExpectedOrder(Order.PROPERTY_CREATED) // For N
.addExpectedOrder(Order.PROPERTY_CREATED) // For SOUND
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.END_ENTRY)
.addExpectedOrder(Order.END);
parser.addInterpreter(interpreter);
// Use parse() to check we
parser.parse(inputStream);
interpreter.verify();
} finally {
inputStream.close();
}
inputStream = getContext().getResources().openRawResource(R.raw.v21_multiple_entry);
try {
VCardParser parser = new VCardParser_V21();
MockVCardInterpreter interpreter = new MockVCardInterpreter();
interpreter.addExpectedOrder(Order.START)
.addExpectedOrder(Order.START_ENTRY)
.addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
.addExpectedOrder(Order.PROPERTY_CREATED) // For N
.addExpectedOrder(Order.PROPERTY_CREATED) // For SOUND
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
.addExpectedOrder(Order.END_ENTRY)
.addExpectedOrder(Order.END);
parser.addInterpreter(interpreter);
parser.parseOne(inputStream);
interpreter.verify();
} finally {
inputStream.close();
}
}
}
@@ -0,0 +1,98 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.test.AndroidTestCase;
import com.android.vcard.VCardConfig;
import com.android.vcard.tests.testutils.VCardVerifier;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import java.util.Arrays;
/**
* Tests confirming utilities for vCard tests work fine.
*
* Now that the foundation classes for vCard test cases became too complicated to
* rely on without testing itself.
*/
public class VCardTestUtilsTests extends AndroidTestCase {
public void testShouldFailAtPropertyNodeVerification() {
boolean failureDetected = false;
try {
final VCardVerifier verifier = new VCardVerifier(this);
verifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_GENERIC, R.raw.v21_backslash);
verifier.addPropertyNodesVerifierElem()
.addExpectedNodeWithOrder("N", ";A;B\\;C\\;;D;:E;\\\\;--", // wrong
Arrays.asList("", "A;B\\", "C\\;", "D", ":E", "\\\\", ""))
.addExpectedNodeWithOrder("FN", "A;B\\C\\;D:E\\\\");
verifier.verify();
} catch (AssertionFailedError e) {
failureDetected = true;
}
if (!failureDetected) {
TestCase.fail("Test case that should fail actually succeeded.");
}
}
public void testShouldFailAtContentValueVerification() {
boolean failureDetected = false;
try {
final VCardVerifier verifier = new VCardVerifier(this);
verifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_GENERIC, R.raw.v21_backslash);
verifier.addContentValuesVerifierElem()
.addExpected(StructuredName.CONTENT_ITEM_TYPE)
.put(StructuredName.GIVEN_NAME, "A;B\\")
.put(StructuredName.MIDDLE_NAME, "C\\;")
.put(StructuredName.PREFIX, "D")
.put(StructuredName.SUFFIX, ":E");
// DISPLAY_NAME is missing.
verifier.verify();
} catch (AssertionFailedError e) {
failureDetected = true;
}
if (!failureDetected) {
TestCase.fail("Test case that should fail actually succeeded.");
}
}
public void testShouldFailAtLineVerification() {
boolean failureDetected = false;
try {
final VCardVerifier verifier = new VCardVerifier(this);
verifier.initForExportTest(VCardConfig.VCARD_TYPE_V30_GENERIC);
verifier.addInputEntry().addContentValues(StructuredName.CONTENT_ITEM_TYPE)
.put(StructuredName.FAMILY_NAME, "\\")
.put(StructuredName.GIVEN_NAME, ";")
.put(StructuredName.MIDDLE_NAME, ",")
.put(StructuredName.PREFIX, "\n")
.put(StructuredName.DISPLAY_NAME, "[<{Unescaped:Asciis}>]");
verifier.addLineVerifierElem()
.addExpected("TEL:1") // wrong
.addExpected("FN:[<{Unescaped:Asciis}>]");
verifier.verify();
} catch (AssertionFailedError e) {
failureDetected = true;
}
if (!failureDetected) {
TestCase.fail("Test case that should fail actually succeeded.");
}
}
}
@@ -0,0 +1,144 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests;
import android.text.TextUtils;
import com.android.vcard.VCardUtils;
import junit.framework.TestCase;
import java.util.List;
public class VCardUtilsTests extends TestCase {
public void testContainsOnlyPrintableAscii() {
assertTrue(VCardUtils.containsOnlyPrintableAscii((String)null));
assertTrue(VCardUtils.containsOnlyPrintableAscii((String[])null));
assertTrue(VCardUtils.containsOnlyPrintableAscii((List<String>)null));
assertTrue(VCardUtils.containsOnlyPrintableAscii(""));
assertTrue(VCardUtils.containsOnlyPrintableAscii("abcdefghijklmnopqrstuvwxyz"));
assertTrue(VCardUtils.containsOnlyPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
StringBuilder builder = new StringBuilder();
for (int i = 0x20; i < 0x7F; i++) {
builder.append((char)i);
}
assertTrue(VCardUtils.containsOnlyPrintableAscii(builder.toString()));
assertTrue(VCardUtils.containsOnlyPrintableAscii("\r\n"));
assertFalse(VCardUtils.containsOnlyPrintableAscii("\u0019"));
assertFalse(VCardUtils.containsOnlyPrintableAscii("\u007F"));
}
public void testContainsOnlyNonCrLfPrintableAscii() {
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((String)null));
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((String[])null));
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii((List<String>)null));
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii(""));
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("abcdefghijklmnopqrstuvwxyz"));
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
StringBuilder builder = new StringBuilder();
for (int i = 0x20; i < 0x7F; i++) {
builder.append((char)i);
}
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii(builder.toString()));
assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\u0019"));
assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\u007F"));
assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\r"));
assertFalse(VCardUtils.containsOnlyNonCrLfPrintableAscii("\n"));
}
public void testContainsOnlyAlphaDigitHyphen() {
assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((String)null));
assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((String[])null));
assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen((List<String>)null));
assertTrue(VCardUtils.containsOnlyAlphaDigitHyphen(""));
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("abcdefghijklmnopqrstuvwxyz"));
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
assertTrue(VCardUtils.containsOnlyNonCrLfPrintableAscii("0123456789-"));
for (int i = 0; i < 0x30; i++) {
if (i == 0x2D) { // -
continue;
}
assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
}
for (int i = 0x3A; i < 0x41; i++) {
assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
}
for (int i = 0x5B; i < 0x61; i++) {
assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
}
for (int i = 0x7B; i < 0x100; i++) {
assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
}
}
public void testToStringAvailableAsV30ParamValue() {
// Smoke tests.
assertEquals("HOME", VCardUtils.toStringAsV30ParamValue("HOME"));
assertEquals("TEL", VCardUtils.toStringAsV30ParamValue("TEL"));
assertEquals("PAGER", VCardUtils.toStringAsV30ParamValue("PAGER"));
assertTrue(TextUtils.isEmpty(VCardUtils.toStringAsV30ParamValue("")));
assertTrue(TextUtils.isEmpty(VCardUtils.toStringAsV30ParamValue(null)));
assertTrue(TextUtils.isEmpty(VCardUtils.toStringAsV30ParamValue(" \t")));
// non-Ascii must be allowed
assertEquals("\u4E8B\u52D9\u6240",
VCardUtils.toStringAsV30ParamValue("\u4E8B\u52D9\u6240"));
// Reported as bug report.
assertEquals("\u8D39", VCardUtils.toStringAsV30ParamValue("\u8D39"));
assertEquals("\"comma,separated\"",
VCardUtils.toStringAsV30ParamValue("comma,separated"));
assertEquals("\"colon:aware\"",
VCardUtils.toStringAsV30ParamValue("colon:aware"));
// CTL characters.
assertEquals("CTLExample",
VCardUtils.toStringAsV30ParamValue("CTL\u0001Example"));
assertTrue(TextUtils.isEmpty(
VCardUtils.toStringAsV30ParamValue("\u0001\u0002\u0003")));
// DQUOTE must be removed.
assertEquals("quoted",
VCardUtils.toStringAsV30ParamValue("\"quoted\""));
// DQUOTE must be removed basically, but we should detect a space, which
// require us to use DQUOTE again.
// Right-side has one more illegal dquote to test quote-handle code thoroughly.
assertEquals("\"Already quoted\"",
VCardUtils.toStringAsV30ParamValue("\"Already quoted\"\""));
}
public void testAppearsLikeAndroidVCardQuotedPrintableByLength() {
assertFalse(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("="));
assertFalse(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=1"));
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12"));
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12="));
assertFalse(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12=1"));
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12=12"));
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12=12="));
}
public void testAppearsLikeAndroidVCardQuotedPrintableByContent() {
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("==="));
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("===="));
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("======="));
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12=12="));
assertTrue(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12=34="));
assertFalse(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=123"));
assertFalse(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=123="));
assertFalse(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("_12="));
assertFalse(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12_"));
assertFalse(VCardUtils.appearsLikeAndroidVCardQuotedPrintable("=12=34_56="));
}
}
@@ -0,0 +1,36 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests;
import com.android.vcard.exception.VCardAgentNotSupportedException;
import junit.framework.TestCase;
public class VCardAgentNotSupportedExceptionTest extends TestCase {
static final String TEST_MESSAGE = "message";
public void testExceptionWithoutMessage() {
VCardAgentNotSupportedException exception = new VCardAgentNotSupportedException();
assertNull(exception.getMessage());
}
public void testExceptionWithMessage() {
VCardAgentNotSupportedException exception = new VCardAgentNotSupportedException(
TEST_MESSAGE);
assertEquals(exception.getMessage(), TEST_MESSAGE);
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests;
import com.android.vcard.exception.VCardException;
import junit.framework.TestCase;
public class VCardExceptionTest extends TestCase {
static final String TEST_MESSAGE = "message";
public void testExceptionWithoutMessage() {
VCardException exception = new VCardException();
assertNull(exception.getMessage());
}
public void testExceptionWithMessage() {
VCardException exception = new VCardException(TEST_MESSAGE);
assertEquals(exception.getMessage(), TEST_MESSAGE);
}
}
@@ -0,0 +1,36 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests;
import com.android.vcard.exception.VCardInvalidCommentLineException;
import junit.framework.TestCase;
public class VCardInvalidCommentLineExceptionTest extends TestCase {
static final String TEST_MESSAGE = "message";
public void testExceptionWithoutMessage() {
VCardInvalidCommentLineException exception = new VCardInvalidCommentLineException();
assertNull(exception.getMessage());
}
public void testExceptionWithMessage() {
VCardInvalidCommentLineException exception = new VCardInvalidCommentLineException(
TEST_MESSAGE);
assertEquals(exception.getMessage(), TEST_MESSAGE);
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests;
import com.android.vcard.exception.VCardInvalidLineException;
import junit.framework.TestCase;
public class VCardInvalidLineExceptionTest extends TestCase {
static final String TEST_MESSAGE = "message";
public void testExceptionWithoutMessage() {
VCardInvalidLineException exception = new VCardInvalidLineException();
assertNull(exception.getMessage());
}
public void testExceptionWithMessage() {
VCardInvalidLineException exception = new VCardInvalidLineException(TEST_MESSAGE);
assertEquals(exception.getMessage(), TEST_MESSAGE);
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests;
import com.android.vcard.exception.VCardNestedException;
import junit.framework.TestCase;
public class VCardNestedExceptionTest extends TestCase {
static final String TEST_MESSAGE = "message";
public void testExceptionWithoutMessage() {
VCardNestedException exception = new VCardNestedException();
assertNull(exception.getMessage());
}
public void testExceptionWithMessage() {
VCardNestedException exception = new VCardNestedException(TEST_MESSAGE);
assertEquals(exception.getMessage(), TEST_MESSAGE);
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests;
import com.android.vcard.exception.VCardNotSupportedException;
import junit.framework.TestCase;
public class VCardNotSupportedExceptionTest extends TestCase {
static final String TEST_MESSAGE = "message";
public void testExceptionWithoutMessage() {
VCardNotSupportedException exception = new VCardNotSupportedException();
assertNull(exception.getMessage());
}
public void testExceptionWithMessage() {
VCardNotSupportedException exception = new VCardNotSupportedException(TEST_MESSAGE);
assertEquals(exception.getMessage(), TEST_MESSAGE);
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests;
import com.android.vcard.exception.VCardVersionException;
import junit.framework.TestCase;
public class VCardVersionExceptionTest extends TestCase {
static final String TEST_MESSAGE = "message";
public void testExceptionWithoutMessage() {
VCardVersionException exception = new VCardVersionException();
assertNull(exception.getMessage());
}
public void testExceptionWithMessage() {
VCardVersionException exception = new VCardVersionException(TEST_MESSAGE);
assertEquals(exception.getMessage(), TEST_MESSAGE);
}
}
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.vcard.tests.testutils;
import android.content.ContentValues;
import android.provider.ContactsContract.Data;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* The class representing one contact, which should contain multiple ContentValues like
* StructuredName, Email, etc.
* </p>
*/
public final class ContactEntry {
private final List<ContentValues> mContentValuesList = new ArrayList<ContentValues>();
public ContentValuesBuilder addContentValues(String mimeType) {
ContentValues contentValues = new ContentValues();
contentValues.put(Data.MIMETYPE, mimeType);
mContentValuesList.add(contentValues);
return new ContentValuesBuilder(contentValues);
}
public List<ContentValues> getList() {
return mContentValuesList;
}
}
@@ -0,0 +1,82 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests.testutils;
import android.content.ContentValues;
/**
* ContentValues-like class which enables users to chain put() methods and restricts
* the other methods.
*/
public class ContentValuesBuilder {
private final ContentValues mContentValues;
public ContentValuesBuilder(final ContentValues contentValues) {
mContentValues = contentValues;
}
public ContentValuesBuilder put(String key, String value) {
mContentValues.put(key, value);
return this;
}
/*
public ContentValuesBuilder put(String key, Byte value) {
mContentValues.put(key, value);
return this;
}
public ContentValuesBuilder put(String key, Short value) {
mContentValues.put(key, value);
return this;
}*/
public ContentValuesBuilder put(String key, Integer value) {
mContentValues.put(key, value);
return this;
}
/*
public ContentValuesBuilder put(String key, Long value) {
mContentValues.put(key, value);
return this;
}
public ContentValuesBuilder put(String key, Float value) {
mContentValues.put(key, value);
return this;
}
public ContentValuesBuilder put(String key, Double value) {
mContentValues.put(key, value);
return this;
}
public ContentValuesBuilder put(String key, Boolean value) {
mContentValues.put(key, value);
return this;
}*/
public ContentValuesBuilder put(String key, byte[] value) {
mContentValues.put(key, value);
return this;
}
public ContentValuesBuilder putNull(String key) {
mContentValues.putNull(key);
return this;
}
}
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests.testutils;
import android.test.AndroidTestCase;
import com.android.vcard.VCardEntry;
import com.android.vcard.VCardEntryHandler;
import java.util.ArrayList;
import java.util.List;
public class ContentValuesVerifier implements VCardEntryHandler {
private List<ContentValuesVerifierElem> mContentValuesVerifierElemList =
new ArrayList<ContentValuesVerifierElem>();
private int mIndex;
public ContentValuesVerifierElem addElem(AndroidTestCase androidTestCase) {
ContentValuesVerifierElem elem = new ContentValuesVerifierElem(androidTestCase);
mContentValuesVerifierElemList.add(elem);
return elem;
}
@Override
public void onStart() {
for (ContentValuesVerifierElem elem : mContentValuesVerifierElemList) {
elem.onParsingStart();
}
}
@Override
public void onEntryCreated(VCardEntry entry) {
AndroidTestCase.assertTrue(mIndex < mContentValuesVerifierElemList.size());
mContentValuesVerifierElemList.get(mIndex).onEntryCreated(entry);
mIndex++;
}
@Override
public void onEnd() {
for (ContentValuesVerifierElem elem : mContentValuesVerifierElemList) {
elem.onParsingEnd();
elem.verifyResolver();
}
}
}
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests.testutils;
import android.content.ContentValues;
import android.provider.ContactsContract.Data;
import android.test.AndroidTestCase;
import com.android.vcard.VCardEntry;
import com.android.vcard.VCardEntryCommitter;
import com.android.vcard.VCardEntryHandler;
public class ContentValuesVerifierElem {
private final ImportTestResolver mResolver;
private final VCardEntryHandler mHandler;
public ContentValuesVerifierElem(AndroidTestCase androidTestCase) {
mResolver = new ImportTestResolver(androidTestCase);
mHandler = new VCardEntryCommitter(mResolver);
}
public ContentValuesBuilder addExpected(String mimeType) {
ContentValues contentValues = new ContentValues();
contentValues.put(Data.MIMETYPE, mimeType);
mResolver.addExpectedContentValues(contentValues);
return new ContentValuesBuilder(contentValues);
}
public void verifyResolver() {
mResolver.verify();
}
public void onParsingStart() {
mHandler.onStart();
}
public void onEntryCreated(VCardEntry entry) {
mHandler.onEntryCreated(entry);
}
public void onParsingEnd() {
mHandler.onEnd();
}
}
@@ -0,0 +1,196 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.vcard.tests.testutils;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Entity;
import android.content.EntityIterator;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
import android.test.AndroidTestCase;
import android.test.mock.MockContentProvider;
import android.test.mock.MockCursor;
import android.util.Log;
import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ExportTestProvider extends MockContentProvider {
final private ArrayList<ContactEntry> mContactEntryList = new ArrayList<ContactEntry>();
private static class MockEntityIterator implements EntityIterator {
private final List<Entity> mEntityList;
private Iterator<Entity> mIterator;
public MockEntityIterator() {
mEntityList = new ArrayList<Entity>();
mIterator = mEntityList.iterator();
}
public void add(List<ContentValues> contentValuesList) {
Entity entity = new Entity(new ContentValues());
for (ContentValues contentValues : contentValuesList) {
entity.addSubValue(Data.CONTENT_URI, contentValues);
}
mEntityList.add(entity);
}
@Override
public boolean hasNext() {
return mIterator.hasNext();
}
@Override
public Entity next() {
return mIterator.next();
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove not supported");
}
@Override
public void reset() {
mIterator = mEntityList.iterator();
}
@Override
public void close() {
}
}
public ExportTestProvider(AndroidTestCase androidTestCase) {
}
public ContactEntry buildInputEntry() {
ContactEntry contactEntry = new ContactEntry();
mContactEntryList.add(contactEntry);
return contactEntry;
}
/**
* <p>
* An old method which had existed but was removed from ContentResolver.
* </p>
* <p>
* We still keep using this method since we don't have a propeer way to know
* which value in the ContentValue corresponds to the entry in Contacts database.
* </p>
*/
public EntityIterator queryEntities(Uri uri,
String selection, String[] selectionArgs, String sortOrder) {
TestCase.assertTrue(uri != null);
TestCase.assertTrue(ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()));
final String authority = uri.getAuthority();
TestCase.assertTrue(RawContacts.CONTENT_URI.getAuthority().equals(authority));
TestCase.assertTrue(selection != null);
TestCase.assertTrue((selection.contains(Data.CONTACT_ID + " IN ")));
TestCase.assertNull(selectionArgs);
MockEntityIterator iterator = new MockEntityIterator();
for (ContactEntry contactEntry : mContactEntryList) {
iterator.add(contactEntry.getList());
}
iterator.reset();
return iterator;
}
@Override
public Cursor query(Uri uri,String[] projection,
String selection, String[] selectionArgs, String sortOrder) {
TestCase.assertTrue(VCardVerifier.CONTACTS_TEST_CONTENT_URI.equals(uri));
// In this test, following arguments are not supported.
TestCase.assertNull(selection);
TestCase.assertNull(selectionArgs);
TestCase.assertNull(sortOrder);
return new MockCursor() {
int mCurrentPosition = -1;
@Override
public int getCount() {
return mContactEntryList.size();
}
@Override
public boolean moveToFirst() {
mCurrentPosition = 0;
return true;
}
@Override
public boolean moveToNext() {
if (mCurrentPosition < mContactEntryList.size() - 1) {
mCurrentPosition++;
return true;
} else {
return false;
}
}
@Override
public boolean isBeforeFirst() {
return mCurrentPosition < 0;
}
@Override
public boolean isLast() {
return mCurrentPosition == mContactEntryList.size() - 1;
}
@Override
public boolean isAfterLast() {
return mCurrentPosition >= mContactEntryList.size();
}
@Override
public int getColumnIndex(String columnName) {
TestCase.assertEquals(Data.CONTACT_ID, columnName);
return 0;
}
@Override
public int getInt(int columnIndex) {
TestCase.assertEquals(0, columnIndex);
TestCase.assertTrue(mCurrentPosition >= 0
&& mCurrentPosition < mContactEntryList.size());
return mCurrentPosition;
}
@Override
public long getLong(int columnIndex) {
return getInt(columnIndex);
}
@Override
public String getString(int columnIndex) {
return String.valueOf(getInt(columnIndex));
}
@Override
public void close() {
}
};
}
}
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.vcard.tests.testutils;
import android.provider.ContactsContract.RawContacts;
import android.test.AndroidTestCase;
import android.test.mock.MockContentResolver;
public class ExportTestResolver extends MockContentResolver {
private final ExportTestProvider mProvider;
public ExportTestResolver(AndroidTestCase androidTestCase) {
mProvider = new ExportTestProvider(androidTestCase);
addProvider(VCardVerifier.VCARD_TEST_AUTHORITY, mProvider);
addProvider(RawContacts.CONTENT_URI.getAuthority(), mProvider);
}
public ContactEntry addInputContactEntry() {
return mProvider.buildInputEntry();
}
public ExportTestProvider getProvider() {
return mProvider;
}
}
@@ -0,0 +1,241 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests.testutils;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentValues;
import android.net.Uri;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
import android.test.mock.MockContentProvider;
import android.text.TextUtils;
import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
public class ImportTestProvider extends MockContentProvider {
private final Map<String, Collection<ContentValues>>
mMimeTypeToExpectedContentValues = new HashMap<String, Collection<ContentValues>>();
public void addExpectedContentValues(ContentValues expectedContentValues) {
final String mimeType = expectedContentValues.getAsString(Data.MIMETYPE);
final Collection<ContentValues> contentValuesCollection;
if (mMimeTypeToExpectedContentValues.containsKey(mimeType)) {
contentValuesCollection = mMimeTypeToExpectedContentValues.get(mimeType);
} else {
contentValuesCollection = new ArrayList<ContentValues>();
mMimeTypeToExpectedContentValues.put(mimeType, contentValuesCollection);
}
contentValuesCollection.add(expectedContentValues);
}
@Override
public ContentProviderResult[] applyBatch(
ArrayList<ContentProviderOperation> operations) {
if (operations == null) {
TestCase.fail("There is no operation.");
}
final int size = operations.size();
ContentProviderResult[] fakeResultArray = new ContentProviderResult[size];
for (int i = 0; i < size; i++) {
Uri uri = Uri.withAppendedPath(RawContacts.CONTENT_URI, String.valueOf(i));
fakeResultArray[i] = new ContentProviderResult(uri);
}
for (int i = 0; i < size; i++) {
ContentProviderOperation operation = operations.get(i);
ContentValues contentValues = operation.resolveValueBackReferences(
fakeResultArray, i);
}
for (int i = 0; i < size; i++) {
ContentProviderOperation operation = operations.get(i);
ContentValues actualContentValues = operation.resolveValueBackReferences(
fakeResultArray, i);
final Uri uri = operation.getUri();
if (uri.equals(RawContacts.CONTENT_URI)) {
TestCase.assertNull(actualContentValues.get(RawContacts.ACCOUNT_NAME));
TestCase.assertNull(actualContentValues.get(RawContacts.ACCOUNT_TYPE));
} else if (uri.equals(Data.CONTENT_URI)) {
final String mimeType = actualContentValues.getAsString(Data.MIMETYPE);
if (!mMimeTypeToExpectedContentValues.containsKey(mimeType)) {
TestCase.fail("Unregistered MimeType " + mimeType);
}
// Remove data meaningless in this unit tests.
// Specifically, Data.DATA1 - DATA7 are set to null or empty String
// regardless of the input, but it may change depending on how
// resolver-related code handles it.
// Here, we ignore these implementation-dependent specs and
// just check whether vCard importer correctly inserts rellevent data.
Set<String> keyToBeRemoved = new HashSet<String>();
for (Entry<String, Object> entry : actualContentValues.valueSet()) {
Object value = entry.getValue();
if (value == null || TextUtils.isEmpty(value.toString())) {
keyToBeRemoved.add(entry.getKey());
}
}
for (String key: keyToBeRemoved) {
actualContentValues.remove(key);
}
/* for testing
Log.d("@@@",
String.format("MimeType: %s, data: %s",
mimeType, actualContentValues.toString())); */
// Remove RAW_CONTACT_ID entry just for safety, since we do not care
// how resolver-related code handles the entry in this unit test,
if (actualContentValues.containsKey(Data.RAW_CONTACT_ID)) {
actualContentValues.remove(Data.RAW_CONTACT_ID);
}
final Collection<ContentValues> contentValuesCollection =
mMimeTypeToExpectedContentValues.get(mimeType);
if (contentValuesCollection.isEmpty()) {
TestCase.fail("ContentValues for MimeType " + mimeType
+ " is not expected at all (" + actualContentValues + ")");
}
boolean checked = false;
for (ContentValues expectedContentValues : contentValuesCollection) {
/*for testing
Log.d("@@@", "expected: "
+ convertToEasilyReadableString(expectedContentValues));
Log.d("@@@", "actual : "
+ convertToEasilyReadableString(actualContentValues));*/
if (equalsForContentValues(expectedContentValues,
actualContentValues)) {
TestCase.assertTrue(contentValuesCollection.remove(expectedContentValues));
checked = true;
break;
}
}
if (!checked) {
final StringBuilder builder = new StringBuilder();
builder.append("\n");
builder.append("Unexpected: ");
builder.append(convertToEasilyReadableString(actualContentValues));
builder.append("\n");
builder.append("Expected : ");
for (ContentValues expectedContentValues : contentValuesCollection) {
builder.append(convertToEasilyReadableString(expectedContentValues));
}
TestCase.fail(builder.toString());
}
} else {
TestCase.fail("Unexpected Uri has come: " + uri);
}
} // for (int i = 0; i < size; i++) {
return fakeResultArray;
}
/**
* Checks all expected ContentValues are consumed during import.
*/
public void verify() {
StringBuilder builder = new StringBuilder();
for (Collection<ContentValues> contentValuesCollection :
mMimeTypeToExpectedContentValues.values()) {
for (ContentValues expectedContentValues: contentValuesCollection) {
builder.append(convertToEasilyReadableString(expectedContentValues));
builder.append("\n");
}
}
if (builder.length() > 0) {
final String failMsg =
"There is(are) remaining expected ContentValues instance(s): \n"
+ builder.toString();
TestCase.fail(failMsg);
}
}
/**
* Utility method to print ContentValues whose content is printed with sorted keys.
*/
private String convertToEasilyReadableString(ContentValues contentValues) {
if (contentValues == null) {
return "null";
}
String mimeTypeValue = "";
SortedMap<String, String> sortedMap = new TreeMap<String, String>();
for (Entry<String, Object> entry : contentValues.valueSet()) {
final String key = entry.getKey();
final Object value = entry.getValue();
final String valueString = (value != null ? value.toString() : null);
if (Data.MIMETYPE.equals(key)) {
mimeTypeValue = valueString;
} else {
TestCase.assertNotNull(key);
sortedMap.put(key, valueString);
}
}
StringBuilder builder = new StringBuilder();
builder.append(Data.MIMETYPE);
builder.append('=');
builder.append(mimeTypeValue);
for (Entry<String, String> entry : sortedMap.entrySet()) {
final String key = entry.getKey();
final String value = entry.getValue();
builder.append(' ');
builder.append(key);
builder.append("=\"");
builder.append(value);
builder.append('"');
}
return builder.toString();
}
private static boolean equalsForContentValues(
final ContentValues expected, final ContentValues actual) {
if (expected == actual) {
return true;
} else if (expected == null || actual == null || expected.size() != actual.size()) {
return false;
}
for (Entry<String, Object> entry : expected.valueSet()) {
final String key = entry.getKey();
final Object value = entry.getValue();
if (!actual.containsKey(key)) {
return false;
}
// Type mismatch usuall happens as importer doesn't care the type of each value.
// For example, variable type might be Integer when importing the type of TEL,
// while variable type would be String when importing the type of RELATION.
final Object actualValue = actual.get(key);
if (value instanceof byte[]) {
if (!Arrays.equals((byte[])value, (byte[])actualValue)) {
byte[] e = (byte[])value;
byte[] a = (byte[])actualValue;
return false;
}
} else if (!value.equals(actualValue) &&
!value.toString().equals(actualValue.toString())) {
return false;
}
}
return true;
}
}
@@ -0,0 +1,56 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests.testutils;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentValues;
import android.provider.ContactsContract.RawContacts;
import android.test.AndroidTestCase;
import android.test.mock.MockContentResolver;
import java.util.ArrayList;
public class ImportTestResolver extends MockContentResolver {
private final ImportTestProvider mProvider;
public ImportTestResolver(AndroidTestCase androidTestCase) {
mProvider = new ImportTestProvider();
}
@Override
public ContentProviderResult[] applyBatch(String authority,
ArrayList<ContentProviderOperation> operations) {
equalsString(authority, RawContacts.CONTENT_URI.toString());
return mProvider.applyBatch(operations);
}
public void addExpectedContentValues(ContentValues expectedContentValues) {
mProvider.addExpectedContentValues(expectedContentValues);
}
public void verify() {
mProvider.verify();
}
private static boolean equalsString(String a, String b) {
if (a == null || a.length() == 0) {
return b == null || b.length() == 0;
} else {
return a.equals(b);
}
}
}
@@ -0,0 +1,52 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests.testutils;
import android.test.AndroidTestCase;
import junit.framework.TestCase;
import java.util.ArrayList;
public class LineVerifier {
private final AndroidTestCase mAndroidTestCase;
private final ArrayList<LineVerifierElem> mLineVerifierElemList;
private int mVCardType;
private int index;
public LineVerifier(AndroidTestCase androidTestCase, int vcardType) {
mAndroidTestCase = androidTestCase;
mLineVerifierElemList = new ArrayList<LineVerifierElem>();
mVCardType = vcardType;
}
public LineVerifierElem addLineVerifierElem() {
LineVerifierElem lineVerifier = new LineVerifierElem(mAndroidTestCase, mVCardType);
mLineVerifierElemList.add(lineVerifier);
return lineVerifier;
}
public void verify(String vcard) {
if (index >= mLineVerifierElemList.size()) {
TestCase.fail("Insufficient number of LineVerifier (" + index + ")");
}
final LineVerifierElem lineVerifier = mLineVerifierElemList.get(index);
lineVerifier.verify(vcard);
index++;
}
}
@@ -0,0 +1,105 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.vcard.tests.testutils;
import android.test.AndroidTestCase;
import android.text.TextUtils;
import com.android.vcard.VCardConfig;
import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.List;
public class LineVerifierElem {
private final List<String> mExpectedLineList = new ArrayList<String>();
private final int mVCardType;
public LineVerifierElem(AndroidTestCase androidTestCase, int vcardType) {
mVCardType = vcardType;
}
public LineVerifierElem addExpected(final String line) {
if (!TextUtils.isEmpty(line)) {
mExpectedLineList.add(line);
}
return this;
}
public void verify(final String vcard) {
final String[] lineArray = vcard.split("\\r?\\n");
final int length = lineArray.length;
boolean beginExists = false;
boolean endExists = false;
boolean versionExists = false;
for (int i = 0; i < length; i++) {
final String line = lineArray[i];
if (TextUtils.isEmpty(line)) {
continue;
}
if ("BEGIN:VCARD".equalsIgnoreCase(line)) {
if (beginExists) {
TestCase.fail("Multiple \"BEGIN:VCARD\" line found");
} else {
beginExists = true;
continue;
}
} else if ("END:VCARD".equalsIgnoreCase(line)) {
if (endExists) {
TestCase.fail("Multiple \"END:VCARD\" line found");
} else {
endExists = true;
continue;
}
} else if ((VCardConfig.isVersion21(mVCardType) ? "VERSION:2.1" :
(VCardConfig.isVersion30(mVCardType) ? "VERSION:3.0" :
"VERSION:4.0")).equalsIgnoreCase(line)) {
if (versionExists) {
TestCase.fail("Multiple VERSION line + found");
} else {
versionExists = true;
continue;
}
}
if (!beginExists) {
TestCase.fail("Property other than BEGIN came before BEGIN property: " + line);
} else if (endExists) {
TestCase.fail("Property other than END came after END property: " + line);
}
final int index = mExpectedLineList.indexOf(line);
if (index >= 0) {
mExpectedLineList.remove(index);
} else {
TestCase.fail("Unexpected line: " + line);
}
}
if (!mExpectedLineList.isEmpty()) {
StringBuffer buffer = new StringBuffer();
for (String expectedLine : mExpectedLineList) {
buffer.append(expectedLine);
buffer.append("\n");
}
TestCase.fail("Expected line(s) not found:" + buffer.toString());
}
}
}
@@ -0,0 +1,205 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests.testutils;
import android.content.ContentValues;
import com.android.vcard.VCardEntry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* <p>
* The class representing one property (e.g. "N;ENCODING=UTF-8:family:given:middle:prefix:suffix").
* </p>
* <p>
* Previously used in main vCard handling code but now exists only for testing.
* </p>
* <p>
* Especially useful for testing parser code (VCardParser), since all properties can be
* checked via this class unlike {@link VCardEntry}, which only emits the result of
* interpretation of the content of each vCard. We cannot know whether vCard parser or
* {@link VCardEntry} is wrong without this class.
* </p>
*/
public class PropertyNode {
public String propName;
public String propValue;
public List<String> propValue_vector;
/** Store value as byte[],after decode.
* Used when propValue is encoded by something like BASE64, QUOTED-PRINTABLE, etc.
*/
public byte[] propValue_bytes;
/**
* param store: key=paramType, value=paramValue
* Note that currently PropertyNode class does not support multiple param-values
* defined in vCard 3.0 (See also RFC 2426). multiple-values are stored as
* one String value like "A,B", not ["A", "B"]...
* TODO: fix this.
*/
public ContentValues paramMap;
/** Only for TYPE=??? param store. */
public Set<String> paramMap_TYPE;
/** Store group values. Used only in VCard. */
public Set<String> propGroupSet;
public PropertyNode() {
propName = "";
propValue = "";
propValue_vector = new ArrayList<String>();
paramMap = new ContentValues();
paramMap_TYPE = new HashSet<String>();
propGroupSet = new HashSet<String>();
}
public PropertyNode(
String propName, String propValue, List<String> propValue_vector,
byte[] propValue_bytes, ContentValues paramMap, Set<String> paramMap_TYPE,
Set<String> propGroupSet) {
if (propName != null) {
this.propName = propName;
} else {
this.propName = "";
}
if (propValue != null) {
this.propValue = propValue;
} else {
this.propValue = "";
}
if (propValue_vector != null) {
this.propValue_vector = propValue_vector;
} else {
this.propValue_vector = new ArrayList<String>();
}
this.propValue_bytes = propValue_bytes;
if (paramMap != null) {
this.paramMap = paramMap;
} else {
this.paramMap = new ContentValues();
}
if (paramMap_TYPE != null) {
this.paramMap_TYPE = paramMap_TYPE;
} else {
this.paramMap_TYPE = new HashSet<String>();
}
if (propGroupSet != null) {
this.propGroupSet = propGroupSet;
} else {
this.propGroupSet = new HashSet<String>();
}
}
@Override
public int hashCode() {
// vCard may contain more than one same line in one entry, while HashSet or any other
// library which utilize hashCode() does not honor that, so intentionally throw an
// Exception.
throw new UnsupportedOperationException(
"PropertyNode does not provide hashCode() implementation intentionally.");
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof PropertyNode)) {
return false;
}
PropertyNode node = (PropertyNode)obj;
if (propName == null || !propName.equals(node.propName)) {
return false;
} else if (!paramMap_TYPE.equals(node.paramMap_TYPE)) {
return false;
} else if (!paramMap_TYPE.equals(node.paramMap_TYPE)) {
return false;
} else if (!propGroupSet.equals(node.propGroupSet)) {
return false;
}
if (propValue_bytes != null && Arrays.equals(propValue_bytes, node.propValue_bytes)) {
return true;
} else {
if (!propValue.equals(node.propValue)) {
return false;
}
// The value in propValue_vector is not decoded even if it should be
// decoded by BASE64 or QUOTED-PRINTABLE. When the size of propValue_vector
// is 1, the encoded value is stored in propValue, so we do not have to
// check it.
return (propValue_vector.equals(node.propValue_vector) ||
propValue_vector.size() == 1 ||
node.propValue_vector.size() == 1);
}
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("propName: ");
builder.append(propName);
builder.append(", paramMap: ");
builder.append(paramMap.toString());
builder.append(", paramMap_TYPE: [");
boolean first = true;
for (String elem : paramMap_TYPE) {
if (first) {
first = false;
} else {
builder.append(", ");
}
builder.append('"');
builder.append(elem);
builder.append('"');
}
builder.append("]");
if (!propGroupSet.isEmpty()) {
builder.append(", propGroupSet: [");
first = true;
for (String elem : propGroupSet) {
if (first) {
first = false;
} else {
builder.append(", ");
}
builder.append('"');
builder.append(elem);
builder.append('"');
}
builder.append("]");
}
if (propValue_vector != null && propValue_vector.size() > 1) {
builder.append(", propValue_vector size: ");
builder.append(propValue_vector.size());
}
if (propValue_bytes != null) {
builder.append(", propValue_bytes size: ");
builder.append(propValue_bytes.length);
}
builder.append(", propValue: \"");
builder.append(propValue);
builder.append("\"");
return builder.toString();
}
}
@@ -0,0 +1,88 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests.testutils;
import android.test.AndroidTestCase;
import com.android.vcard.VCardParser;
import com.android.vcard.VCardUtils;
import com.android.vcard.exception.VCardException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class PropertyNodesVerifier extends VNodeBuilder {
private final List<PropertyNodesVerifierElem> mPropertyNodesVerifierElemList;
private final AndroidTestCase mAndroidTestCase;
private int mIndex;
public PropertyNodesVerifier(AndroidTestCase testCase) {
super();
mPropertyNodesVerifierElemList = new ArrayList<PropertyNodesVerifierElem>();
mAndroidTestCase = testCase;
}
public PropertyNodesVerifierElem addPropertyNodesVerifierElem() {
PropertyNodesVerifierElem elem = new PropertyNodesVerifierElem(mAndroidTestCase);
mPropertyNodesVerifierElemList.add(elem);
return elem;
}
public void verify(int resId, int vcardType) throws IOException, VCardException {
verify(mAndroidTestCase.getContext().getResources().openRawResource(resId), vcardType);
}
public void verify(int resId, int vcardType, final VCardParser parser)
throws IOException, VCardException {
verify(mAndroidTestCase.getContext().getResources().openRawResource(resId),
vcardType, parser);
}
public void verify(InputStream is, int vcardType) throws IOException, VCardException {
final VCardParser parser = VCardUtils.getAppropriateParser(vcardType);
verify(is, vcardType, parser);
}
public void verify(InputStream is, int vcardType, final VCardParser parser)
throws IOException, VCardException {
parser.addInterpreter(this);
try {
parser.parse(is);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
}
}
}
}
@Override
public void onEntryStarted() {
super.onEntryStarted();
AndroidTestCase.assertTrue(mIndex < mPropertyNodesVerifierElemList.size());
}
@Override
public void onEntryEnded() {
mPropertyNodesVerifierElemList.get(mIndex).verify(getCurrentVNode());
super.onEntryEnded();
mIndex++;
}
}
@@ -0,0 +1,330 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests.testutils;
import android.content.ContentValues;
import android.test.AndroidTestCase;
import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
/**
* Utility class which verifies input VNode.
*
* This class first checks whether each propertyNode in the VNode is in the
* "ordered expected property list".
* If the node does not exist in the "ordered list", the class refers to
* "unorderd expected property set" and checks the node is expected somewhere.
*/
public class PropertyNodesVerifierElem {
public static class TypeSet extends HashSet<String> {
public TypeSet(String ... array) {
super(Arrays.asList(array));
}
}
public static class GroupSet extends HashSet<String> {
public GroupSet(String ... array) {
super(Arrays.asList(array));
}
}
private final HashMap<String, List<PropertyNode>> mOrderedNodeMap;
// Intentionally use ArrayList instead of Set, assuming there may be more than one
// exactly same objects.
private final ArrayList<PropertyNode> mUnorderedNodeList;
public PropertyNodesVerifierElem(AndroidTestCase androidTestCase) {
mOrderedNodeMap = new HashMap<String, List<PropertyNode>>();
mUnorderedNodeList = new ArrayList<PropertyNode>();
}
// WithOrder
public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName, String propValue) {
return addExpectedNodeWithOrder(propName, propValue, null, null, null, null, null);
}
public PropertyNodesVerifierElem addExpectedNodeWithOrder(
String propName, String propValue, ContentValues contentValues) {
return addExpectedNodeWithOrder(propName, propValue, null,
null, contentValues, null, null);
}
public PropertyNodesVerifierElem addExpectedNodeWithOrder(
String propName, List<String> propValueList, ContentValues contentValues) {
return addExpectedNodeWithOrder(propName, null, propValueList,
null, contentValues, null, null);
}
public PropertyNodesVerifierElem addExpectedNodeWithOrder(
String propName, String propValue, List<String> propValueList) {
return addExpectedNodeWithOrder(propName, propValue, propValueList, null,
null, null, null);
}
public PropertyNodesVerifierElem addExpectedNodeWithOrder(
String propName, List<String> propValueList) {
final String propValue = concatinateListWithSemiColon(propValueList);
return addExpectedNodeWithOrder(propName, propValue.toString(), propValueList,
null, null, null, null);
}
public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName, String propValue,
TypeSet paramMap_TYPE) {
return addExpectedNodeWithOrder(propName, propValue, null,
null, null, paramMap_TYPE, null);
}
public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName,
List<String> propValueList, TypeSet paramMap_TYPE) {
return addExpectedNodeWithOrder(propName, null, propValueList, null, null,
paramMap_TYPE, null);
}
public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName,
List<String> propValueList, ContentValues paramMap, TypeSet paramMap_TYPE) {
return addExpectedNodeWithOrder(propName, null, propValueList, null, paramMap,
paramMap_TYPE, null);
}
public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName, String propValue,
ContentValues paramMap, TypeSet paramMap_TYPE) {
return addExpectedNodeWithOrder(propName, propValue, null, null,
paramMap, paramMap_TYPE, null);
}
public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName, String propValue,
List<String> propValueList, TypeSet paramMap_TYPE) {
return addExpectedNodeWithOrder(propName, propValue, propValueList, null, null,
paramMap_TYPE, null);
}
public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName, String propValue,
List<String> propValueList, ContentValues paramMap) {
return addExpectedNodeWithOrder(propName, propValue, propValueList, null, paramMap,
null, null);
}
public PropertyNodesVerifierElem addExpectedNodeWithOrder(String propName, String propValue,
List<String> propValueList, byte[] propValue_bytes,
ContentValues paramMap, TypeSet paramMap_TYPE, GroupSet propGroupSet) {
if (propValue == null && propValueList != null) {
propValue = concatinateListWithSemiColon(propValueList);
}
final PropertyNode propertyNode = new PropertyNode(propName,
propValue, propValueList, propValue_bytes,
paramMap, paramMap_TYPE, propGroupSet);
List<PropertyNode> expectedNodeList = mOrderedNodeMap.get(propName);
if (expectedNodeList == null) {
expectedNodeList = new ArrayList<PropertyNode>();
mOrderedNodeMap.put(propName, expectedNodeList);
}
expectedNodeList.add(propertyNode);
return this;
}
// WithoutOrder
public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue) {
return addExpectedNode(propName, propValue, null, null, null, null, null);
}
public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
ContentValues contentValues) {
return addExpectedNode(propName, propValue, null, null, contentValues, null, null);
}
public PropertyNodesVerifierElem addExpectedNode(String propName,
List<String> propValueList, ContentValues contentValues) {
return addExpectedNode(propName, null,
propValueList, null, contentValues, null, null);
}
public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
List<String> propValueList) {
return addExpectedNode(propName, propValue, propValueList, null, null, null, null);
}
public PropertyNodesVerifierElem addExpectedNode(String propName,
List<String> propValueList) {
return addExpectedNode(propName, null, propValueList,
null, null, null, null);
}
public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
TypeSet paramMap_TYPE) {
return addExpectedNode(propName, propValue, null, null, null, paramMap_TYPE, null);
}
public PropertyNodesVerifierElem addExpectedNode(String propName,
List<String> propValueList, TypeSet paramMap_TYPE) {
final String propValue = concatinateListWithSemiColon(propValueList);
return addExpectedNode(propName, propValue, propValueList, null, null,
paramMap_TYPE, null);
}
public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
List<String> propValueList, TypeSet paramMap_TYPE) {
return addExpectedNode(propName, propValue, propValueList, null, null,
paramMap_TYPE, null);
}
public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
ContentValues paramMap, TypeSet paramMap_TYPE) {
return addExpectedNode(propName, propValue, null, null,
paramMap, paramMap_TYPE, null);
}
public PropertyNodesVerifierElem addExpectedNode(String propName, String propValue,
List<String> propValueList, byte[] propValue_bytes,
ContentValues paramMap, TypeSet paramMap_TYPE, GroupSet propGroupSet) {
if (propValue == null && propValueList != null) {
propValue = concatinateListWithSemiColon(propValueList);
}
mUnorderedNodeList.add(new PropertyNode(propName, propValue,
propValueList, propValue_bytes, paramMap, paramMap_TYPE, propGroupSet));
return this;
}
public void verify(VNode vnode) {
for (PropertyNode actualNode : vnode.propList) {
verifyNode(actualNode.propName, actualNode);
}
if (!mOrderedNodeMap.isEmpty() || !mUnorderedNodeList.isEmpty()) {
final List<String> expectedProps = new ArrayList<String>();
for (List<PropertyNode> nodes : mOrderedNodeMap.values()) {
for (PropertyNode node : nodes) {
if (!expectedProps.contains(node.propName)) {
expectedProps.add(node.propName);
}
}
}
for (PropertyNode node : mUnorderedNodeList) {
if (!expectedProps.contains(node.propName)) {
expectedProps.add(node.propName);
}
}
TestCase.fail("Expected property " + Arrays.toString(expectedProps.toArray())
+ " was not found.");
}
}
private void verifyNode(final String propName, final PropertyNode actualNode) {
final List<PropertyNode> expectedNodeList = mOrderedNodeMap.get(propName);
final int size = (expectedNodeList != null ? expectedNodeList.size() : 0);
if (size > 0) {
for (int i = 0; i < size; i++) {
final PropertyNode expectedNode = expectedNodeList.get(i);
final List<PropertyNode> expectedButDifferentValueList =
new ArrayList<PropertyNode>();
if (expectedNode.propName.equals(propName)) {
if (expectedNode.equals(actualNode)) {
expectedNodeList.remove(i);
if (expectedNodeList.size() == 0) {
mOrderedNodeMap.remove(propName);
}
return;
} else {
expectedButDifferentValueList.add(expectedNode);
}
}
// "actualNode" is not in ordered expected list.
// Try looking over unordered expected list.
if (tryFoundExpectedNodeFromUnorderedList(actualNode,
expectedButDifferentValueList)) {
return;
}
if (!expectedButDifferentValueList.isEmpty()) {
// Same propName exists but with different value(s).
failWithExpectedNodeList(propName, actualNode,
expectedButDifferentValueList);
} else {
// There's no expected node with same propName.
TestCase.fail("Unexpected property \"" + propName + "\" exists.");
}
}
} else {
List<PropertyNode> expectedButDifferentValueList =
new ArrayList<PropertyNode>();
if (tryFoundExpectedNodeFromUnorderedList(actualNode, expectedButDifferentValueList)) {
return;
} else {
if (!expectedButDifferentValueList.isEmpty()) {
// Same propName exists but with different value(s).
failWithExpectedNodeList(propName, actualNode,
expectedButDifferentValueList);
} else {
// There's no expected node with same propName.
TestCase.fail("Unexpected property \"" + propName + "\" exists.");
}
}
}
}
private String concatinateListWithSemiColon(List<String> array) {
StringBuffer buffer = new StringBuffer();
boolean first = true;
for (String propValueElem : array) {
if (first) {
first = false;
} else {
buffer.append(';');
}
buffer.append(propValueElem);
}
return buffer.toString();
}
private boolean tryFoundExpectedNodeFromUnorderedList(PropertyNode actualNode,
List<PropertyNode> expectedButDifferentValueList) {
final String propName = actualNode.propName;
int unorderedListSize = mUnorderedNodeList.size();
for (int i = 0; i < unorderedListSize; i++) {
PropertyNode unorderedExpectedNode = mUnorderedNodeList.get(i);
if (unorderedExpectedNode.propName.equals(propName)) {
if (unorderedExpectedNode.equals(actualNode)) {
mUnorderedNodeList.remove(i);
return true;
}
expectedButDifferentValueList.add(unorderedExpectedNode);
}
}
return false;
}
private void failWithExpectedNodeList(String propName, PropertyNode actualNode,
List<PropertyNode> expectedNodeList) {
StringBuilder builder = new StringBuilder();
for (PropertyNode expectedNode : expectedNodeList) {
builder.append("expected: ");
builder.append(expectedNode.toString());
builder.append("\n");
}
TestCase.fail("Property \"" + propName + "\" has wrong value.\n"
+ builder.toString()
+ " actual: " + actualNode.toString());
}
}
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests.testutils;
import android.content.ContentValues;
import android.test.AndroidTestCase;
import com.android.vcard.VCardConfig;
import com.android.vcard.tests.testutils.VCardVerifier;
/**
* BaseClass for vCard unit tests with utility classes.
* Please do not add each unit test here.
*/
public abstract class VCardTestsBase extends AndroidTestCase {
public static final int V21 = VCardConfig.VCARD_TYPE_V21_GENERIC;
public static final int V30 = VCardConfig.VCARD_TYPE_V30_GENERIC;
public static final int V40 = VCardConfig.VCARD_TYPE_V40_GENERIC;
// Do not modify these during tests.
protected final ContentValues mContentValuesForQP;
protected final ContentValues mContentValuesForSJis;
protected final ContentValues mContentValuesForUtf8;
protected final ContentValues mContentValuesForQPAndSJis;
protected final ContentValues mContentValuesForQPAndUtf8;
protected final ContentValues mContentValuesForBase64V21;
protected final ContentValues mContentValuesForBase64V30;
protected VCardVerifier mVerifier;
/**
* true when we shouldn't call {@link VCardVerifier#verify()}.
*/
private boolean mSkipVerification;
public VCardTestsBase() {
super();
// Not using constants in vCard code since it may be wrong.
mContentValuesForQP = new ContentValues();
mContentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
mContentValuesForSJis = new ContentValues();
mContentValuesForSJis.put("CHARSET", "SHIFT_JIS");
mContentValuesForUtf8 = new ContentValues();
mContentValuesForUtf8.put("CHARSET", "UTF-8");
mContentValuesForQPAndSJis = new ContentValues();
mContentValuesForQPAndSJis.put("ENCODING", "QUOTED-PRINTABLE");
mContentValuesForQPAndSJis.put("CHARSET", "SHIFT_JIS");
mContentValuesForQPAndUtf8 = new ContentValues();
mContentValuesForQPAndUtf8.put("ENCODING", "QUOTED-PRINTABLE");
mContentValuesForQPAndUtf8.put("CHARSET", "UTF-8");
mContentValuesForBase64V21 = new ContentValues();
mContentValuesForBase64V21.put("ENCODING", "BASE64");
mContentValuesForBase64V30 = new ContentValues();
mContentValuesForBase64V30.put("ENCODING", "b");
}
@Override
public void testAndroidTestCaseSetupProperly() {
super.testAndroidTestCaseSetupProperly();
mSkipVerification = true;
}
/**
* Calls super's {@link #setUp()} and prepares {@link VCardVerifier}. We call
* {@link VCardVerifier#verify()} on {@link #tearDown()}.
*/
@Override
public final void setUp() throws Exception{
super.setUp();
mVerifier = new VCardVerifier(this);
mSkipVerification = false;
}
/**
* Calls super's {@link #tearDown()} and {@link VCardVerifier#verify()}.
*/
@Override
public final void tearDown() throws Exception {
// We don't want to forget to call verify() as it makes unit test successful silently even
// when it shouldn't be, while each test case tends become so large to manage and sometimes
// we had forgotten to call the method. That is why we override setUp()/tearDown() here.
if (!mSkipVerification) {
mVerifier.verify();
}
super.tearDown();
}
}
@@ -0,0 +1,400 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.vcard.tests.testutils;
import android.content.ContentResolver;
import android.content.EntityIterator;
import android.database.Cursor;
import android.net.Uri;
import android.test.AndroidTestCase;
import android.test.mock.MockContext;
import android.text.TextUtils;
import android.util.Log;
import com.android.vcard.VCardComposer;
import com.android.vcard.VCardConfig;
import com.android.vcard.VCardEntryConstructor;
import com.android.vcard.VCardParser;
import com.android.vcard.VCardUtils;
import com.android.vcard.exception.VCardException;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
/**
* <p>
* The class lets users checks that given expected vCard data are same as given actual vCard data.
* Able to verify both vCard importer/exporter.
* </p>
* <p>
* First a user has to initialize the object by calling either
* {@link #initForImportTest(int, int)} or {@link #initForExportTest(int)}.
* "Round trip test" (import -> export -> import, or export -> import -> export) is not supported.
* </p>
*/
public class VCardVerifier {
private static final String LOG_TAG = "VCardVerifier";
private static final boolean DEBUG = true;
/**
* Special URI for testing.
*/
/* package */ static final String VCARD_TEST_AUTHORITY = "com.android.unit_tests.vcard";
private static final Uri VCARD_TEST_AUTHORITY_URI =
Uri.parse("content://" + VCARD_TEST_AUTHORITY);
/* package */ static final Uri CONTACTS_TEST_CONTENT_URI =
Uri.withAppendedPath(VCARD_TEST_AUTHORITY_URI, "contacts");
private static class CustomMockContext extends MockContext {
final ContentResolver mResolver;
public CustomMockContext(ContentResolver resolver) {
mResolver = resolver;
}
@Override
public ContentResolver getContentResolver() {
return mResolver;
}
}
private final AndroidTestCase mAndroidTestCase;
private int mVCardType;
private boolean mIsDoCoMo;
// Only one of them must be non-empty.
private ExportTestResolver mExportTestResolver;
private InputStream mInputStream;
// To allow duplication, use list instead of set.
// When null, we don't need to do the verification.
private PropertyNodesVerifier mPropertyNodesVerifier;
private LineVerifier mLineVerifier;
private ContentValuesVerifier mContentValuesVerifier;
private boolean mInitialized;
private boolean mVerified = false;
private String mCharset;
private String mExceptionContents;
// Called by VCardTestsBase
public VCardVerifier(AndroidTestCase androidTestCase) {
mAndroidTestCase = androidTestCase;
mExportTestResolver = null;
mInputStream = null;
mInitialized = false;
mVerified = false;
}
// Should be called at the beginning of each import test.
public void initForImportTest(int vcardType, int resId) {
if (mInitialized) {
AndroidTestCase.fail("Already initialized");
}
mVCardType = vcardType;
mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
setInputResourceId(resId);
mInitialized = true;
}
// Should be called at the beginning of each export test.
public void initForExportTest(int vcardType) {
initForExportTest(vcardType, "UTF-8");
}
public void initForExportTest(int vcardType, String charset) {
if (mInitialized) {
AndroidTestCase.fail("Already initialized");
}
mExportTestResolver = new ExportTestResolver(mAndroidTestCase);
mVCardType = vcardType;
mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
mInitialized = true;
if (TextUtils.isEmpty(charset)) {
mCharset = "UTF-8";
} else {
mCharset = charset;
}
}
private void setInputResourceId(int resId) {
final InputStream inputStream =
mAndroidTestCase.getContext().getResources().openRawResource(resId);
if (inputStream == null) {
AndroidTestCase.fail("Wrong resId: " + resId);
}
setInputStream(inputStream);
}
private void setInputStream(InputStream inputStream) {
if (mExportTestResolver != null) {
AndroidTestCase.fail("addInputEntry() is called.");
} else if (mInputStream != null) {
AndroidTestCase.fail("InputStream is already set");
}
mInputStream = inputStream;
}
public ContactEntry addInputEntry() {
if (!mInitialized) {
AndroidTestCase.fail("Not initialized");
}
if (mInputStream != null) {
AndroidTestCase.fail("setInputStream is called");
}
return mExportTestResolver.addInputContactEntry();
}
public PropertyNodesVerifierElem addPropertyNodesVerifierElemWithoutVersion() {
if (!mInitialized) {
AndroidTestCase.fail("Not initialized");
}
if (mPropertyNodesVerifier == null) {
mPropertyNodesVerifier = new PropertyNodesVerifier(mAndroidTestCase);
}
return mPropertyNodesVerifier.addPropertyNodesVerifierElem();
}
public PropertyNodesVerifierElem addPropertyNodesVerifierElem() {
final PropertyNodesVerifierElem elem = addPropertyNodesVerifierElemWithoutVersion();
final String versionString;
if (VCardConfig.isVersion21(mVCardType)) {
versionString = "2.1";
} else if (VCardConfig.isVersion30(mVCardType)) {
versionString = "3.0";
} else if (VCardConfig.isVersion40(mVCardType)) {
versionString = "4.0";
} else {
throw new RuntimeException("Unexpected vcard type during a unit test");
}
elem.addExpectedNodeWithOrder("VERSION", versionString);
return elem;
}
public PropertyNodesVerifierElem addPropertyNodesVerifierElemWithEmptyName() {
if (!mInitialized) {
AndroidTestCase.fail("Not initialized");
}
final PropertyNodesVerifierElem elem = addPropertyNodesVerifierElem();
if (VCardConfig.isVersion40(mVCardType)) {
elem.addExpectedNodeWithOrder("FN", "");
} else if (VCardConfig.isVersion30(mVCardType)) {
elem.addExpectedNodeWithOrder("N", "");
elem.addExpectedNodeWithOrder("FN", "");
} else if (mIsDoCoMo) {
elem.addExpectedNodeWithOrder("N", "");
}
return elem;
}
public LineVerifierElem addLineVerifierElem() {
if (!mInitialized) {
AndroidTestCase.fail("Not initialized");
}
if (mLineVerifier == null) {
mLineVerifier = new LineVerifier(mAndroidTestCase, mVCardType);
}
return mLineVerifier.addLineVerifierElem();
}
public ContentValuesVerifierElem addContentValuesVerifierElem() {
if (!mInitialized) {
AndroidTestCase.fail("Not initialized");
}
if (mContentValuesVerifier == null) {
mContentValuesVerifier = new ContentValuesVerifier();
}
return mContentValuesVerifier.addElem(mAndroidTestCase);
}
public void addVCardExceptionVerifier(String contents) {
mExceptionContents = contents;
}
/**
* Sets up sub-verifiers correctly and tries to parse vCard as {@link InputStream}.
* Errors around InputStream must be handled outside this method.
*
* Used both from {@link #verifyForImportTest()} and from {@link #verifyForExportTest()}.
*/
private void verifyWithInputStream(InputStream is) throws IOException {
try {
// Note: we must not specify charset toward vCard parsers. This code checks whether
// those parsers are able to encode given binary without any extra information for
// charset.
final VCardParser parser = VCardUtils.getAppropriateParser(mVCardType);
if (mContentValuesVerifier != null) {
final VCardEntryConstructor constructor = new VCardEntryConstructor(mVCardType);
constructor.addEntryHandler(mContentValuesVerifier);
parser.addInterpreter(constructor);
}
if (mPropertyNodesVerifier != null) {
parser.addInterpreter(mPropertyNodesVerifier);
}
parser.parse(is);
if (mExceptionContents != null) {
// exception contents exists, we expect an exception to occur.
AndroidTestCase.fail();
}
} catch (VCardException e) {
if (mExceptionContents != null) {
AndroidTestCase.assertTrue(e.getMessage().contains(mExceptionContents));
} else {
Log.e(LOG_TAG, "VCardException", e);
AndroidTestCase.fail("Unexpected VCardException: " + e.getMessage());
}
}
}
private void verifyOneVCardForExport(final String vcard) {
if (DEBUG) Log.d(LOG_TAG, vcard);
InputStream is = null;
try {
is = new ByteArrayInputStream(vcard.getBytes(mCharset));
verifyWithInputStream(is);
} catch (IOException e) {
AndroidTestCase.fail("Unexpected IOException: " + e.getMessage());
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
AndroidTestCase.fail("Unexpected IOException: " + e.getMessage());
}
}
}
}
public void verify() {
if (!mInitialized) {
TestCase.fail("Not initialized.");
}
if (mVerified) {
TestCase.fail("verify() was called twice.");
}
if (mInputStream != null) {
if (mExportTestResolver != null){
TestCase.fail("There are two input sources.");
}
verifyForImportTest();
} else if (mExportTestResolver != null){
verifyForExportTest();
} else {
TestCase.fail("No input is determined");
}
mVerified = true;
}
private void verifyForImportTest() {
if (mLineVerifier != null) {
AndroidTestCase.fail("Not supported now.");
}
try {
verifyWithInputStream(mInputStream);
} catch (IOException e) {
AndroidTestCase.fail("IOException was thrown: " + e.getMessage());
} finally {
if (mInputStream != null) {
try {
mInputStream.close();
} catch (IOException e) {
}
}
}
}
public static EntityIterator mockGetEntityIteratorMethod(
final ContentResolver resolver,
final Uri uri, final String selection,
final String[] selectionArgs, final String sortOrder) {
if (ExportTestResolver.class.equals(resolver.getClass())) {
return ((ExportTestResolver)resolver).getProvider().queryEntities(
uri, selection, selectionArgs, sortOrder);
}
Log.e(LOG_TAG, "Unexpected provider given.");
return null;
}
private Method getMockGetEntityIteratorMethod()
throws SecurityException, NoSuchMethodException {
return this.getClass().getMethod("mockGetEntityIteratorMethod",
ContentResolver.class, Uri.class, String.class, String[].class, String.class);
}
private void verifyForExportTest() {
final CustomMockContext context = new CustomMockContext(mExportTestResolver);
final ContentResolver resolver = context.getContentResolver();
final VCardComposer composer = new VCardComposer(context, mVCardType, mCharset);
// projection is ignored.
final Cursor cursor = resolver.query(CONTACTS_TEST_CONTENT_URI, null, null, null, null);
Method mockGetEntityIteratorMethod = null;
try {
mockGetEntityIteratorMethod = getMockGetEntityIteratorMethod();
} catch (Exception e) {
AndroidTestCase.fail("Exception thrown: " + e);
}
AndroidTestCase.assertNotNull(mockGetEntityIteratorMethod);
composer.setGetEntityIteratorMethod(mockGetEntityIteratorMethod);
if (!composer.init(cursor)) {
AndroidTestCase.fail("init() failed. Reason: " + composer.getErrorReason());
}
AndroidTestCase.assertFalse(composer.isAfterLast());
try {
while (!composer.isAfterLast()) {
final String vcard = composer.createOneEntry();
AndroidTestCase.assertNotNull(vcard);
if (mLineVerifier != null) {
mLineVerifier.verify(vcard);
}
verifyOneVCardForExport(vcard);
}
} finally {
composer.terminate();
}
}
public String buildVCardForExportTest() {
final CustomMockContext context = new CustomMockContext(mExportTestResolver);
final ContentResolver resolver = context.getContentResolver();
final VCardComposer composer = new VCardComposer(context, mVCardType, mCharset);
// projection is ignored.
final Cursor cursor = resolver.query(CONTACTS_TEST_CONTENT_URI, null, null, null, null);
Method mockGetEntityIteratorMethod = null;
try {
mockGetEntityIteratorMethod = getMockGetEntityIteratorMethod();
} catch (Exception e) {
AndroidTestCase.fail("Exception thrown: " + e);
}
AndroidTestCase.assertNotNull(mockGetEntityIteratorMethod);
composer.setGetEntityIteratorMethod(mockGetEntityIteratorMethod);
if (!composer.init(cursor)) {
AndroidTestCase.fail("init() failed. Reason: " + composer.getErrorReason());
}
AndroidTestCase.assertFalse(composer.isAfterLast());
final String vcard = composer.createOneEntry();
AndroidTestCase.assertNotNull(vcard);
composer.terminate();
return vcard;
}
}
@@ -0,0 +1,28 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests.testutils;
import java.util.ArrayList;
/**
* Previously used in main vCard handling code but now exists only for testing.
*
* TODO: remove this and relevant classes. Given we can have appropriate test cases for
* VCardEntry and VCardProperty, we won't need redundancy here.
*/
public class VNode {
public ArrayList<PropertyNode> propList = new ArrayList<PropertyNode>();
}
@@ -0,0 +1,173 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vcard.tests.testutils;
import com.android.vcard.VCardConfig;
import com.android.vcard.VCardInterpreter;
import com.android.vcard.VCardProperty;
import com.android.vcard.VCardUtils;
import android.content.ContentValues;
import android.util.Base64;
import android.util.Log;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* <p>
* The class storing the parse result to custom datastruct:
* {@link VNode}, and {@link PropertyNode}.
* Maybe several vcard instance, so use vNodeList to store.
* </p>
* <p>
* This is called VNode, not VCardNode, since it was used for expressing vCalendar (iCal).
* </p>
*/
public class VNodeBuilder implements VCardInterpreter {
private static String LOG_TAG = "VNodeBuilder";
private List<VNode> mVNodeList = new ArrayList<VNode>();
private VNode mCurrentVNode;
/**
* The charset using which VParser parses the text.
*/
private String mSourceCharset;
/**
* The charset with which byte array is encoded to String.
*/
private String mTargetCharset;
private boolean mStrictLineBreakParsing;
public VNodeBuilder() {
this(VCardConfig.DEFAULT_IMPORT_CHARSET, false);
}
public VNodeBuilder(String targetCharset, boolean strictLineBreakParsing) {
mSourceCharset = VCardConfig.DEFAULT_INTERMEDIATE_CHARSET;
if (targetCharset != null) {
mTargetCharset = targetCharset;
} else {
mTargetCharset = VCardConfig.DEFAULT_IMPORT_CHARSET;
}
mStrictLineBreakParsing = strictLineBreakParsing;
}
@Override
public void onVCardStarted() {
}
@Override
public void onVCardEnded() {
}
@Override
public void onEntryStarted() {
mCurrentVNode = new VNode();
mVNodeList.add(mCurrentVNode);
}
@Override
public void onEntryEnded() {
int lastIndex = mVNodeList.size() - 1;
mVNodeList.remove(lastIndex--);
mCurrentVNode = lastIndex >= 0 ? mVNodeList.get(lastIndex) : null;
}
@Override
public void onPropertyCreated(VCardProperty property) {
// TODO: remove PropertyNode.
PropertyNode propNode = new PropertyNode();
propNode.propName = property.getName();
List<String> groupList = property.getGroupList();
if (groupList != null) {
propNode.propGroupSet.addAll(groupList);
}
Map<String, Collection<String>> propertyParameterMap = property.getParameterMap();
for (String paramType : propertyParameterMap.keySet()) {
Collection<String> paramValueList = propertyParameterMap.get(paramType);
if (paramType.equalsIgnoreCase("TYPE")) {
propNode.paramMap_TYPE.addAll(paramValueList);
} else {
for (String paramValue : paramValueList) {
propNode.paramMap.put(paramType, paramValue);
}
}
}
// TODO: just redundant
if (property.getRawValue() == null) {
propNode.propValue_bytes = null;
propNode.propValue_vector.clear();
propNode.propValue_vector.add("");
propNode.propValue = "";
return;
}
final List<String> values = property.getValueList();
if (values == null || values.size() == 0) {
propNode.propValue_vector.clear();
propNode.propValue_vector.add("");
propNode.propValue = "";
} else {
propNode.propValue_vector.addAll(values);
propNode.propValue = listToString(propNode.propValue_vector);
}
propNode.propValue_bytes = property.getByteValue();
mCurrentVNode.propList.add(propNode);
}
private String listToString(List<String> list){
int size = list.size();
if (size > 1) {
StringBuilder typeListB = new StringBuilder();
for (String type : list) {
typeListB.append(type).append(";");
}
int len = typeListB.length();
if (len > 0 && typeListB.charAt(len - 1) == ';') {
return typeListB.substring(0, len - 1);
}
return typeListB.toString();
} else if (size == 1) {
return list.get(0);
} else {
return "";
}
}
public String getResult(){
throw new RuntimeException("Not supported");
}
public List<VNode> getVNodeList() {
return mVNodeList;
}
public VNode getCurrentVNode() {
return mCurrentVNode;
}
}