From 1a44d5dcabc18cd5ef111f732ccff91683a1a093 Mon Sep 17 00:00:00 2001 From: Neal Nguyen Date: Wed, 13 Jan 2010 10:42:43 -0800 Subject: Phase 2 of test cleanup: moving test files from AndroidTests closer to their sources. Most of these are file moves; a couple notable exceptions are the changes due to the move, and fixing up test code: - database/DatabaseCursorTest.java - database/DatabaseStatementTest.java - net/UriTest.java --- sax/tests/saxtests/Android.mk | 14 + sax/tests/saxtests/AndroidManifest.xml | 36 + sax/tests/saxtests/res/raw/youtube.xml | 1852 ++++++++++++++++++++ .../src/android/sax/ExpatPerformanceTest.java | 125 ++ .../saxtests/src/android/sax/SafeSaxTest.java | 541 ++++++ 5 files changed, 2568 insertions(+) create mode 100644 sax/tests/saxtests/Android.mk create mode 100644 sax/tests/saxtests/AndroidManifest.xml create mode 100644 sax/tests/saxtests/res/raw/youtube.xml create mode 100644 sax/tests/saxtests/src/android/sax/ExpatPerformanceTest.java create mode 100644 sax/tests/saxtests/src/android/sax/SafeSaxTest.java (limited to 'sax') diff --git a/sax/tests/saxtests/Android.mk b/sax/tests/saxtests/Android.mk new file mode 100644 index 0000000..836711b --- /dev/null +++ b/sax/tests/saxtests/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# We only want this apk build for tests. +LOCAL_MODULE_TAGS := tests + +# Include all test java files. +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_PACKAGE_NAME := FrameworksSaxTests + +include $(BUILD_PACKAGE) + diff --git a/sax/tests/saxtests/AndroidManifest.xml b/sax/tests/saxtests/AndroidManifest.xml new file mode 100644 index 0000000..c66844d --- /dev/null +++ b/sax/tests/saxtests/AndroidManifest.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + diff --git a/sax/tests/saxtests/res/raw/youtube.xml b/sax/tests/saxtests/res/raw/youtube.xml new file mode 100644 index 0000000..fedaeac --- /dev/null +++ b/sax/tests/saxtests/res/raw/youtube.xml @@ -0,0 +1,1852 @@ + + + + + http://dm5.google.com/feeds/standardfeeds/top_rated + 2007-05-01T18:13:20.333Z + Top Rated - Beta + http://www.youtube.com/img/pic_youtubelogo_123x63.gif + + + + + + YouTube + http://www.youtube.com/ + + YouTube data API + + 99 + 1 + 25 + + http://dm5.google.com/feeds/videos/nojWJ6-XmeQ + 2006-09-01T15:13:19.000Z + 2006-09-01T15:13:19.000Z + + + + + + + + + Banned Commercial - Condoms + + + + + + bannedcommercials + http://dm5.google.com/feeds/users/bannedcommercials + + + Banned Commercial - Condoms + Banned Commercial - Condoms + + Banned, Commercial, Condoms, funny, hilarious, + comedy, humor + + + + Comedy + + + + + + + + + + + + http://dm5.google.com/feeds/videos/JahdnOQ9XCA + 2006-09-01T17:25:14.000Z + 2006-09-01T17:25:14.000Z + + + + + + + + + + + + + Banned Commercial - Bill Clinton Voodoo doll very + funny + + + + + + + bannedcommercials + http://dm5.google.com/feeds/users/bannedcommercials + + + Banned Commercial - Bill Clinton Voodoo + doll very funny + + Banned Commercial - Bill Clinton + Voodoo doll very funny + + Banned, Commercial, Bill, Clinton, Voodoo, doll, + very, funny, humor, hilarious, comedy + + + + Entertainment + + + + + + + + + + + + http://dm5.google.com/feeds/videos/VcQIwbvGRKU + 2006-09-03T05:32:33.000Z + 2006-09-03T05:32:33.000Z + + + + + + + + + + Amazing funny TV Commercial - Talk Talk + + + + + + bannedcommercials + http://dm5.google.com/feeds/users/bannedcommercials + + + Amazing funny TV Commercial - Talk Talk + + Amazing funny TV Commercial - Talk + Talk + + Amazing, funny, TV, Commercial, Talk, humor, + hilarious, awesome + + + + Entertainment + + + + + + + + + + + + http://dm5.google.com/feeds/videos/JsD6uEZsIsU + 2006-11-28T16:42:47.000Z + 2006-11-28T16:42:47.000Z + + + + + + Andy Mckee - Rylynn - Acoustic Guitar - + www.candyrat.com + + + + + + + rpoland + http://dm5.google.com/feeds/users/rpoland + + + Andy Mckee - Rylynn - Acoustic Guitar - + www.candyrat.com + + Filmed Nov, 2006. + + CD - Art of Motion + + http://www.candyrat.com + + Transcriptions Available at: + + http://www.candyrat.com + + Andy, Mckee, Acoustic, Guitar + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/dt1fB62cGbo + 2006-11-19T16:02:11.000Z + 2006-11-19T16:02:11.000Z + + + + + + + + + Andy Mckee - Africa - Toto - www.candyrat.com + + + + + + rpoland + http://dm5.google.com/feeds/users/rpoland + + + Andy Mckee - Africa - Toto - + www.candyrat.com + + Andy Mckee + + filmed, Nov, 2006. + + CD - Dreamcatcher + http://www.candyrat.com + + Transcriptions Available at: + http://www.candyrat.com + + Andy, Mckee, Acoustic, Guitar, Fingerstyle, Africa, + Toto + + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/Ddn4MGaS3N4 + 2006-11-25T21:38:20.000Z + 2006-11-25T21:38:20.000Z + + + + + + Andy Mckee - Guitar - Drifting - www.candyrat.com + + + + + + + rpoland + http://dm5.google.com/feeds/users/rpoland + + + Andy Mckee - Guitar - Drifting - + www.candyrat.com + + Acoustic Guitar + + Drifting - Andy Mckee's Original Song + + filmed, Nov, 2006. + + CD - Art of Motion + + http://www.candyrat.com + + Transcriptions Available at: + + http://www.candyrat.com + + Acoustic, Guitar, Andy, Mckee + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/SmVAWKfJ4Go + 2005-12-13T02:25:05.000Z + 2005-12-13T02:25:05.000Z + + + + Cash Hurt + + + + + + beachbuggy + http://dm5.google.com/feeds/users/beachbuggy + + + Cash Hurt + cash hurt + Cash, hurt + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/AbndgwfG22k + 2006-06-18T18:07:46.000Z + 2006-06-18T18:07:46.000Z + + + + + + + + + + + + + + + + "AirTap!" + + + + + + erikmongrain + http://dm5.google.com/feeds/users/erikmongrain + + + "AirTap!" + MY FIRST CD IS NOW AVAILABLE ON MY + WEBSITE IN MP3 FORMAT !!! IN STORE MAY 2007 ! + www.erikmongrain.com + + Myself playing a composition I made 6 years ago in the streets + of Spain when I was travelling around.That was on "Belle et Bum" + (popular music show in Quebec ). + + Acoustic, Guitar, Michael, Hedges, Preston, Reed, + Don, Ross, Erik, Mongrain, Tommy, Emmanuel, Leo, Kottke + + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/2Neop9OVaB8 + 2006-11-21T23:03:29.000Z + 2006-11-21T23:03:29.000Z + + + + + + + + + + + + + + + + + + + + + Remember The Name - Highlight Reel Video + + + + + + fortminor + http://dm5.google.com/feeds/users/fortminor + + + Remember The Name - Highlight Reel Video + + Fort Minor Remember The Name + "Highlight Reel" video - made from the winning video clips + submitted for the Fort Minor / Fuse Remember The Name contest - + congratulations to all the winners! + + Fort, Minor, Fuse, Highlight, Reel, Action, Sports, + Remember, The, Name, Rising, Ties, Mike, Shinoda, Skate, + Scooter, Tricks, Flips, Dunks + + + + Entertainment + + + + + + + + + + + + http://dm5.google.com/feeds/videos/QKXWAE8YYxY + 2006-02-03T00:07:12.000Z + 2006-02-03T00:07:12.000Z + + + + + + + + + + + + Resident Evil 4 -- Stupid MF + + + + + + raypinot + http://dm5.google.com/feeds/users/raypinot + + + Resident Evil 4 -- Stupid MF + Video I made for Resident Evil 4 + using "Separate Ways" and footage and that didn't make it into + my first video, "Vicinity of Obscenity" This video is done to + the song "Stupid MF" by Mindless Self Indulgence. + + http://www.help-lara-and-ray.com/ + + Resident, Evil, Four, RE4, Mindless, Self, + Indulgence, MSI, Stupid, MF + + + + Games + + + + + + + + + + + + http://dm5.google.com/feeds/videos/zQoAUI84amI + 2006-02-02T23:36:31.000Z + 2006-02-02T23:36:31.000Z + + + + + + + + + + + + Resident Evil 4 -- Vicinity of Obscenity + + + + + + raypinot + http://dm5.google.com/feeds/users/raypinot + + + Resident Evil 4 -- Vicinity of Obscenity + + Music video I made For Resident Evil + 4 (PS2), using the System of a Down song, "Vicinity of + Obscenity" + + + http://www.help-lara-and-ray.com/ + + Resident, Evil, Four, RE4, System, Down, SOAD, + Vicinity, of, Obscenity + + + + Games + + + + + + + + + + + + http://dm5.google.com/feeds/videos/JzqumbhfxRo + 2006-11-07T16:59:10.000Z + 2006-11-07T16:59:10.000Z + + + + + + + + + + + + + + + + + Amateur - Lasse Gjertsen + + + + + + lassegg + http://dm5.google.com/feeds/users/lassegg + + + Amateur - Lasse Gjertsen + I've taken my hyperactive editing + style a step further! Hope you'll enjoy it! + + If you want to download the audio from this video, go to + http://www11.nrk.no/urort/user/?id=36781 + It's a norwegian page where I uploaded some of my music. (Lytt = + Listen to, Last ned = Download) + + Oh shit, I forgot to put this in the video, and now it's too + late to change it: + Thanks to my friend Mattis for letting me borrow the drum kit. + Also thanks to the person letting me use her piano, but she + didn't want her name here :P + + And now; to you people saying I'm ripping off Michel Gondry: + I've seen his video with the drumkit called "Drumb and Drumber". + It's here on youtube somewhere. His video and my video are + different because of one very important detail: Gondy filmed + himself doing drumming sequences and LOOPED them, while I hit + each drum and piano chord seperately and edited them together. + This is a very big difference if you have any idea about video + editing. Actually, there is a short sequence of 5 sec where he + does cut the beat, but I didn't notice this until recently, + which makes me an idiot. But I still don't think it's a rip off, + only similar. SO one question to you guys: If I write a song + which includes the words "love" and "tight", am I ripping off + The Beatles?? :P I met Michel Gondry in Milan, Italy and asked + him. He didn't really give me a clear answer, but it seemed like + he thought so. Either that or he didn't like my clothes. Lol. + + amateur, lasse, gjertsen, drumkit, drums, piano, + music, norsk, norwegian, lassegg, hyperactive, editing, ass, + and, titties + + + + Film + + + + + + + + + + + + + http://dm5.google.com/feeds/videos/YxQrPXPSVhQ + 2006-06-17T16:04:49.000Z + 2006-06-17T16:04:49.000Z + + + Evanescence + + + + + + luke4leanne + http://dm5.google.com/feeds/users/luke4leanne + + + Evanescence + Evanescence-My Immortal + + Evanescence + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/O9mEKMz2Pvo + 2006-02-15T12:14:08.000Z + 2006-02-15T12:14:08.000Z + + + + + + + + + + Jake Shimabukuro plays "While My Guitar Gently Weeps" + + + + + + + strewth + http://dm5.google.com/feeds/users/strewth + + + Jake Shimabukuro plays "While My Guitar + Gently Weeps" + + Jake Shimabukuro plays "While My + Guitar Gently Weeps" on the ukelele. Amazing. + + Jake, Shimabukuro, While, My, Guitar, Gently, Weeps, + ukelele + + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/rP3qL4UG1TI + 2006-10-27T20:29:34.000Z + 2006-10-27T20:29:34.000Z + + + + + + + + + + + + + + + + + The Woody show "Aries Spears" rap Live105.com + + + + + + Livemorningshow + http://dm5.google.com/feeds/users/Livemorningshow + + + The Woody show "Aries Spears" rap + Live105.com + + Live 105 Morning show "Aries Spears" + rap with Woody,Tony and Ravey. Edited By: + myspace.com/whitemenace + + Woody, Tony, Ravey, Live, 105, radio, morning, show, + Aries, Spears, JayZ, whitemenace, snoop, dog, Q101 + + + + Entertainment + + + + + + + + + + + + http://dm5.google.com/feeds/videos/4NFiu-V7StQ + 2006-05-19T17:11:52.000Z + 2006-05-19T17:11:52.000Z + + + + + + + + + + + Helena - My Chemical Romance - Sims 2 version + + + + + + jaydee227 + http://dm5.google.com/feeds/users/jaydee227 + + + Helena - My Chemical Romance - Sims 2 + version + + This is the 3rd sims movie I made. + you need to watch it carefully or you won't understand the + story. But hope you enjoy :) + + USEFUL LINKS: + + Explanations to the storyline: + http://www.jd-movies.com/helenaexplained.html + + List of the custom content: + http://www.jd-movies.com/helenacc.html + + Movie FAQ: + http://www.jd-movies.com/helenafaq.html + + Download link (MUCH better quality): + http://www.archive.org/download/helenasims2/Helena.wmv + + Helena, My, Chemical, Romance, MCR, Sims, Movie, + machinima, Jaydee + + + + Film + + + + + + + + + + + + http://dm5.google.com/feeds/videos/bGFXKYvH39I + 2006-06-21T17:23:54.000Z + 2006-06-21T17:23:54.000Z + + + + + three days grace-Animal I Have Become + + + + + + jollech69 + http://dm5.google.com/feeds/users/jollech69 + + + three days grace-Animal I Have Become + + By 3 days grace + Three, days, grace + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/V1_OkegYtZI + 2007-03-17T10:45:49.000Z + 2007-03-17T10:45:49.000Z + + + + + + + Yu-Gi-Oh: The Abridged Series - Episode 19 + + + + + + LittleKuriboh + http://dm5.google.com/feeds/users/LittleKuriboh + + + Yu-Gi-Oh: The Abridged Series - Episode 19 + + Imagine Yu-Gi-Oh condensed into + about nine minutes. That's basically what this is. + + Yu-Gi-Oh is the property of Konami and Kazuki Takahasi. + + yugioh, abridged, series, dub, spoof + + + + Comedy + + + + + + + + + + + + http://dm5.google.com/feeds/videos/1A42U-pKP0U + 2006-06-02T16:38:18.000Z + 2006-06-02T16:38:18.000Z + + + + + + ™[LINKIN PARK-From The Inside]™ + + + + + + linkin2789 + http://dm5.google.com/feeds/users/linkin2789 + + + ™[LINKIN PARK-From The Inside]™ + + Video de la canción From The Inside + de Linkin Park. + + LP, FroM, The, Inside + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/s-7UX1xSEfU + 2006-07-18T17:06:52.000Z + 2006-07-18T17:06:52.000Z + + + + + + + + Yu-Gi-Oh: The Abridged Series (Episode 3) + + + + + + LittleKuriboh + http://dm5.google.com/feeds/users/LittleKuriboh + + + Yu-Gi-Oh: The Abridged Series (Episode 3) + + Imagine "Yu-Gi-Oh" condensed into + four minutes. That's basically what this is. + + yugioh, yu-gi-oh, dub, spoof, anime, abridged + + + + Comedy + + + + + + + + + + + + http://dm5.google.com/feeds/videos/V6k3YlcYtS0 + 2006-08-05T22:15:41.000Z + 2006-08-05T22:15:41.000Z + + + + + + + + Yu-Gi-Oh: The Abridged Series (Episode 6) + + + + + + LittleKuriboh + http://dm5.google.com/feeds/users/LittleKuriboh + + + Yu-Gi-Oh: The Abridged Series (Episode 6) + + Imagine "Yu-Gi-Oh" condensed into + four... uh, six minutes. That's basically what this is. + + Yu-Gi-Oh belongs to Kazuki Takahashi + + yu-gi-oh, yugioh, abridged, dub, spoof, anime + + + + Comedy + + + + + + + + + + + + http://dm5.google.com/feeds/videos/HTKs5ZT16PM + 2006-10-23T18:15:56.000Z + 2006-10-23T18:15:56.000Z + + + + + + + + Yu-Gi-Oh: The Abridged Series (Episode 13) + + + + + + LittleKuriboh + http://dm5.google.com/feeds/users/LittleKuriboh + + + Yu-Gi-Oh: The Abridged Series (Episode 13) + + Please ignore the imposter videos. + + Imagine "Yu-Gi-Oh" condensed into five/six minutes. That's + basically what this is. + + Yu-Gi-Oh belongs to Kazuki Takahashi + + yugioh, abridged, series, anime, spoof, dub + + + + Comedy + + + + + + + + + + + + http://dm5.google.com/feeds/videos/MePzWtHqrso + 2006-06-28T00:21:59.000Z + 2006-06-28T00:21:59.000Z + + + + + + Breaking Benjamin - "The Diary of Jane" + + + + + + BrienTA + http://dm5.google.com/feeds/users/BrienTA + + + Breaking Benjamin - "The Diary of Jane" + + Breaking Benjamin - "The Diary of + Jane" + + Breaking, Benjamin, Diary, Jane + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/ElrldD02if0 + 2006-11-20T19:41:52.000Z + 2006-11-20T19:41:52.000Z + + + + + + + + + + + + + + + + + + + Re: How to draw a car in MS. Paint + + + + + + picster + http://dm5.google.com/feeds/users/picster + + + Re: How to draw a car in MS. Paint + + WATCH MY NEW VIDEO!!!! + http://www.youtube.com/watch?v=vUWqRhReaZk + + ---- + Wow! So many nice comments and views :) + I'm very happy you all like it. + + And thank you very much for all the nice emails! + + car, art, paint, draw, automobile, comaro, custom, + concept, how, ms.paint, great, good, awsome, design, artistic, + chip, foose + + + + Film + + + + + + + + + + + + http://dm5.google.com/feeds/videos/Ox0c_1l9al4 + 2006-07-04T01:56:27.000Z + 2006-07-04T01:56:27.000Z + + + + + AMV Comedians 2 (Dane Cook) + + + + + + Rubix89 + http://dm5.google.com/feeds/users/Rubix89 + + + AMV Comedians 2 (Dane Cook) + Anime: Naruto + Comedian: Dane Cook + I know I already did Dane Cook, but I couldnt pass up this joke. + http://www.animemusicvideos.org/members/members_videoinfo.php?v=130820 + + Naruto, Dane, Cook + + + Comedy + + + + + + + + + + + diff --git a/sax/tests/saxtests/src/android/sax/ExpatPerformanceTest.java b/sax/tests/saxtests/src/android/sax/ExpatPerformanceTest.java new file mode 100644 index 0000000..892c490 --- /dev/null +++ b/sax/tests/saxtests/src/android/sax/ExpatPerformanceTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2007 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 android.sax; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.util.Log; +import android.util.Xml; +import org.kxml2.io.KXmlParser; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import com.android.frameworks.saxtests.R; + +public class ExpatPerformanceTest extends AndroidTestCase { + + private static final String TAG = ExpatPerformanceTest.class.getSimpleName(); + + private byte[] mXmlBytes; + + @Override + public void setUp() throws Exception { + super.setUp(); + InputStream in = mContext.getResources().openRawResource(R.raw.youtube); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int length; + while ((length = in.read(buffer)) != -1) { + out.write(buffer, 0, length); + } + mXmlBytes = out.toByteArray(); + + Log.i("***", "File size: " + (mXmlBytes.length / 1024) + "k"); + } + + @LargeTest + public void testPerformance() throws Exception { +// try { +// Debug.startMethodTracing("expat3"); +// for (int i = 0; i < 1; i++) { + runJavaPullParser(); + runSax(); + runExpatPullParser(); +// } +// } finally { +// Debug.stopMethodTracing(); +// } + } + + private InputStream newInputStream() { + return new ByteArrayInputStream(mXmlBytes); + } + + private void runSax() throws IOException, SAXException { + long start = System.currentTimeMillis(); + Xml.parse(newInputStream(), Xml.Encoding.UTF_8, new DefaultHandler()); + long elapsed = System.currentTimeMillis() - start; + Log.i(TAG, "expat SAX: " + elapsed + "ms"); + } + + private void runExpatPullParser() throws XmlPullParserException, IOException { + long start = System.currentTimeMillis(); + XmlPullParser pullParser = Xml.newPullParser(); + pullParser.setInput(newInputStream(), "UTF-8"); + withPullParser(pullParser); + long elapsed = System.currentTimeMillis() - start; + Log.i(TAG, "expat pull: " + elapsed + "ms"); + } + + private void runJavaPullParser() throws XmlPullParserException, IOException { + XmlPullParser pullParser; + long start = System.currentTimeMillis(); + pullParser = new KXmlParser(); + pullParser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); + pullParser.setInput(newInputStream(), "UTF-8"); + withPullParser(pullParser); + long elapsed = System.currentTimeMillis() - start; + Log.i(TAG, "java pull parser: " + elapsed + "ms"); + } + + private static void withPullParser(XmlPullParser pullParser) + throws IOException, XmlPullParserException { + int eventType = pullParser.next(); + while (eventType != XmlPullParser.END_DOCUMENT) { + switch (eventType) { + case XmlPullParser.START_TAG: + pullParser.getName(); +// int nattrs = pullParser.getAttributeCount(); +// for (int i = 0; i < nattrs; ++i) { +// pullParser.getAttributeName(i); +// pullParser.getAttributeValue(i); +// } + break; + case XmlPullParser.END_TAG: + pullParser.getName(); + break; + case XmlPullParser.TEXT: + pullParser.getText(); + break; + } + eventType = pullParser.next(); + } + } +} diff --git a/sax/tests/saxtests/src/android/sax/SafeSaxTest.java b/sax/tests/saxtests/src/android/sax/SafeSaxTest.java new file mode 100644 index 0000000..bee3938 --- /dev/null +++ b/sax/tests/saxtests/src/android/sax/SafeSaxTest.java @@ -0,0 +1,541 @@ +/* + * Copyright (C) 2007 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 android.sax; + +import android.graphics.Bitmap; +import android.sax.Element; +import android.sax.ElementListener; +import android.sax.EndTextElementListener; +import android.sax.RootElement; +import android.sax.StartElementListener; +import android.sax.TextElementListener; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.text.format.Time; +import android.util.Log; +import android.util.Xml; +import com.android.common.XmlUtils; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import com.android.frameworks.saxtests.R; + +public class SafeSaxTest extends AndroidTestCase { + + private static final String TAG = SafeSaxTest.class.getName(); + + private static final String ATOM_NAMESPACE = "http://www.w3.org/2005/Atom"; + private static final String MEDIA_NAMESPACE = "http://search.yahoo.com/mrss/"; + private static final String YOUTUBE_NAMESPACE = "http://gdata.youtube.com/schemas/2007"; + private static final String GDATA_NAMESPACE = "http://schemas.google.com/g/2005"; + + private static class ElementCounter implements ElementListener { + int starts = 0; + int ends = 0; + + public void start(Attributes attributes) { + starts++; + } + + public void end() { + ends++; + } + } + + private static class TextElementCounter implements TextElementListener { + int starts = 0; + String bodies = ""; + + public void start(Attributes attributes) { + starts++; + } + + public void end(String body) { + this.bodies += body; + } + } + + @SmallTest + public void testListener() throws Exception { + String xml = "\n" + + "\n" + + "a\n" + + "\n" + + "\n" + + "b\n" + + "\n" + + "\n"; + + RootElement root = new RootElement(ATOM_NAMESPACE, "feed"); + Element entry = root.requireChild(ATOM_NAMESPACE, "entry"); + Element id = entry.requireChild(ATOM_NAMESPACE, "id"); + + ElementCounter rootCounter = new ElementCounter(); + ElementCounter entryCounter = new ElementCounter(); + TextElementCounter idCounter = new TextElementCounter(); + + root.setElementListener(rootCounter); + entry.setElementListener(entryCounter); + id.setTextElementListener(idCounter); + + Xml.parse(xml, root.getContentHandler()); + + assertEquals(1, rootCounter.starts); + assertEquals(1, rootCounter.ends); + assertEquals(2, entryCounter.starts); + assertEquals(2, entryCounter.ends); + assertEquals(2, idCounter.starts); + assertEquals("ab", idCounter.bodies); + } + + @SmallTest + public void testMissingRequiredChild() throws Exception { + String xml = ""; + RootElement root = new RootElement("feed"); + root.requireChild("entry"); + + try { + Xml.parse(xml, root.getContentHandler()); + fail("expected exception not thrown"); + } catch (SAXException e) { + // Expected. + } + } + + @SmallTest + public void testMixedContent() throws Exception { + String xml = ""; + + RootElement root = new RootElement("feed"); + root.setEndTextElementListener(new EndTextElementListener() { + public void end(String body) { + } + }); + + try { + Xml.parse(xml, root.getContentHandler()); + fail("expected exception not thrown"); + } catch (SAXException e) { + // Expected. + } + } + + @LargeTest + public void testPerformance() throws Exception { + InputStream in = mContext.getResources().openRawResource(R.raw.youtube); + byte[] xmlBytes; + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int length; + while ((length = in.read(buffer)) != -1) { + out.write(buffer, 0, length); + } + xmlBytes = out.toByteArray(); + } finally { + in.close(); + } + + Log.i("***", "File size: " + (xmlBytes.length / 1024) + "k"); + + VideoAdapter videoAdapter = new VideoAdapter(); + ContentHandler handler = newContentHandler(videoAdapter); + for (int i = 0; i < 2; i++) { + pureSaxTest(new ByteArrayInputStream(xmlBytes)); + saxyModelTest(new ByteArrayInputStream(xmlBytes)); + saxyModelTest(new ByteArrayInputStream(xmlBytes), handler); + } + } + + private static void pureSaxTest(InputStream inputStream) throws IOException, SAXException { + long start = System.currentTimeMillis(); + VideoAdapter videoAdapter = new VideoAdapter(); + Xml.parse(inputStream, Xml.Encoding.UTF_8, new YouTubeContentHandler(videoAdapter)); + long elapsed = System.currentTimeMillis() - start; + Log.i(TAG, "pure SAX: " + elapsed + "ms"); + } + + private static void saxyModelTest(InputStream inputStream) throws IOException, SAXException { + long start = System.currentTimeMillis(); + VideoAdapter videoAdapter = new VideoAdapter(); + Xml.parse(inputStream, Xml.Encoding.UTF_8, newContentHandler(videoAdapter)); + long elapsed = System.currentTimeMillis() - start; + Log.i(TAG, "Saxy Model: " + elapsed + "ms"); + } + + private static void saxyModelTest(InputStream inputStream, ContentHandler contentHandler) + throws IOException, SAXException { + long start = System.currentTimeMillis(); + Xml.parse(inputStream, Xml.Encoding.UTF_8, contentHandler); + long elapsed = System.currentTimeMillis() - start; + Log.i(TAG, "Saxy Model (preloaded): " + elapsed + "ms"); + } + + private static class VideoAdapter { + public void addVideo(YouTubeVideo video) { + } + } + + private static ContentHandler newContentHandler(VideoAdapter videoAdapter) { + return new HandlerFactory().newContentHandler(videoAdapter); + } + + private static class HandlerFactory { + YouTubeVideo video; + + public ContentHandler newContentHandler(VideoAdapter videoAdapter) { + RootElement root = new RootElement(ATOM_NAMESPACE, "feed"); + + final VideoListener videoListener = new VideoListener(videoAdapter); + + Element entry = root.getChild(ATOM_NAMESPACE, "entry"); + + entry.setElementListener(videoListener); + + entry.getChild(ATOM_NAMESPACE, "id") + .setEndTextElementListener(new EndTextElementListener() { + public void end(String body) { + video.videoId = body; + } + }); + + entry.getChild(ATOM_NAMESPACE, "published") + .setEndTextElementListener(new EndTextElementListener() { + public void end(String body) { + // TODO(tomtaylor): programmatically get the timezone + video.dateAdded = new Time(Time.TIMEZONE_UTC); + video.dateAdded.parse3339(body); + } + }); + + Element author = entry.getChild(ATOM_NAMESPACE, "author"); + author.getChild(ATOM_NAMESPACE, "name") + .setEndTextElementListener(new EndTextElementListener() { + public void end(String body) { + video.authorName = body; + } + }); + + Element mediaGroup = entry.getChild(MEDIA_NAMESPACE, "group"); + + mediaGroup.getChild(MEDIA_NAMESPACE, "thumbnail") + .setStartElementListener(new StartElementListener() { + public void start(Attributes attributes) { + String url = attributes.getValue("", "url"); + if (video.thumbnailUrl == null && url.length() > 0) { + video.thumbnailUrl = url; + } + } + }); + + mediaGroup.getChild(MEDIA_NAMESPACE, "content") + .setStartElementListener(new StartElementListener() { + public void start(Attributes attributes) { + String url = attributes.getValue("", "url"); + if (url != null) { + video.videoUrl = url; + } + } + }); + + mediaGroup.getChild(MEDIA_NAMESPACE, "player") + .setStartElementListener(new StartElementListener() { + public void start(Attributes attributes) { + String url = attributes.getValue("", "url"); + if (url != null) { + video.playbackUrl = url; + } + } + }); + + mediaGroup.getChild(MEDIA_NAMESPACE, "title") + .setEndTextElementListener(new EndTextElementListener() { + public void end(String body) { + video.title = body; + } + }); + + mediaGroup.getChild(MEDIA_NAMESPACE, "category") + .setEndTextElementListener(new EndTextElementListener() { + public void end(String body) { + video.category = body; + } + }); + + mediaGroup.getChild(MEDIA_NAMESPACE, "description") + .setEndTextElementListener(new EndTextElementListener() { + public void end(String body) { + video.description = body; + } + }); + + mediaGroup.getChild(MEDIA_NAMESPACE, "keywords") + .setEndTextElementListener(new EndTextElementListener() { + public void end(String body) { + video.tags = body; + } + }); + + mediaGroup.getChild(YOUTUBE_NAMESPACE, "duration") + .setStartElementListener(new StartElementListener() { + public void start(Attributes attributes) { + String seconds = attributes.getValue("", "seconds"); + video.lengthInSeconds + = XmlUtils.convertValueToInt(seconds, 0); + } + }); + + mediaGroup.getChild(YOUTUBE_NAMESPACE, "statistics") + .setStartElementListener(new StartElementListener() { + public void start(Attributes attributes) { + String viewCount = attributes.getValue("", "viewCount"); + video.viewCount + = XmlUtils.convertValueToInt(viewCount, 0); + } + }); + + entry.getChild(GDATA_NAMESPACE, "rating") + .setStartElementListener(new StartElementListener() { + public void start(Attributes attributes) { + String average = attributes.getValue("", "average"); + video.rating = average == null + ? 0.0f : Float.parseFloat(average); + } + }); + + return root.getContentHandler(); + } + + class VideoListener implements ElementListener { + + final VideoAdapter videoAdapter; + + public VideoListener(VideoAdapter videoAdapter) { + this.videoAdapter = videoAdapter; + } + + public void start(Attributes attributes) { + video = new YouTubeVideo(); + } + + public void end() { + videoAdapter.addVideo(video); + video = null; + } + } + } + + private static class YouTubeContentHandler extends DefaultHandler { + + final VideoAdapter videoAdapter; + + YouTubeVideo video = null; + StringBuilder builder = null; + + public YouTubeContentHandler(VideoAdapter videoAdapter) { + this.videoAdapter = videoAdapter; + } + + @Override + public void startElement(String uri, String localName, String qName, + Attributes attributes) throws SAXException { + if (uri.equals(ATOM_NAMESPACE)) { + if (localName.equals("entry")) { + video = new YouTubeVideo(); + return; + } + + if (video == null) { + return; + } + + if (!localName.equals("id") + && !localName.equals("published") + && !localName.equals("name")) { + return; + } + this.builder = new StringBuilder(); + return; + + } + + if (video == null) { + return; + } + + if (uri.equals(MEDIA_NAMESPACE)) { + if (localName.equals("thumbnail")) { + String url = attributes.getValue("", "url"); + if (video.thumbnailUrl == null && url.length() > 0) { + video.thumbnailUrl = url; + } + return; + } + + if (localName.equals("content")) { + String url = attributes.getValue("", "url"); + if (url != null) { + video.videoUrl = url; + } + return; + } + + if (localName.equals("player")) { + String url = attributes.getValue("", "url"); + if (url != null) { + video.playbackUrl = url; + } + return; + } + + if (localName.equals("title") + || localName.equals("category") + || localName.equals("description") + || localName.equals("keywords")) { + this.builder = new StringBuilder(); + return; + } + + return; + } + + if (uri.equals(YOUTUBE_NAMESPACE)) { + if (localName.equals("duration")) { + video.lengthInSeconds = XmlUtils.convertValueToInt( + attributes.getValue("", "seconds"), 0); + return; + } + + if (localName.equals("statistics")) { + video.viewCount = XmlUtils.convertValueToInt( + attributes.getValue("", "viewCount"), 0); + return; + } + + return; + } + + if (uri.equals(GDATA_NAMESPACE)) { + if (localName.equals("rating")) { + String average = attributes.getValue("", "average"); + video.rating = average == null + ? 0.0f : Float.parseFloat(average); + } + } + } + + @Override + public void characters(char text[], int start, int length) + throws SAXException { + if (builder != null) { + builder.append(text, start, length); + } + } + + String takeText() { + try { + return builder.toString(); + } finally { + builder = null; + } + } + + @Override + public void endElement(String uri, String localName, String qName) + throws SAXException { + if (video == null) { + return; + } + + if (uri.equals(ATOM_NAMESPACE)) { + if (localName.equals("published")) { + // TODO(tomtaylor): programmatically get the timezone + video.dateAdded = new Time(Time.TIMEZONE_UTC); + video.dateAdded.parse3339(takeText()); + return; + } + + if (localName.equals("name")) { + video.authorName = takeText(); + return; + } + + if (localName.equals("id")) { + video.videoId = takeText(); + return; + } + + if (localName.equals("entry")) { + // Add the video! + videoAdapter.addVideo(video); + video = null; + return; + } + + return; + } + + if (uri.equals(MEDIA_NAMESPACE)) { + if (localName.equals("description")) { + video.description = takeText(); + return; + } + + if (localName.equals("keywords")) { + video.tags = takeText(); + return; + } + + if (localName.equals("category")) { + video.category = takeText(); + return; + } + + if (localName.equals("title")) { + video.title = takeText(); + } + } + } + } + + private static class YouTubeVideo { + public String videoId; // the id used to lookup on YouTube + public String videoUrl; // the url to play the video + public String playbackUrl; // the url to share for users to play video + public String thumbnailUrl; // the url of the thumbnail image + public String title; + public Bitmap bitmap; // cached bitmap of the thumbnail + public int lengthInSeconds; + public int viewCount; // number of times the video has been viewed + public float rating; // ranges from 0.0 to 5.0 + public Boolean triedToLoadThumbnail; + public String authorName; + public Time dateAdded; + public String category; + public String tags; + public String description; + } +} + -- cgit v1.1