diff --git a/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_date.xml b/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_date.xml new file mode 100644 index 00000000..b4aaab5c --- /dev/null +++ b/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_date.xml @@ -0,0 +1,43 @@ + + + Google Expands its Flutter Development Kit To Windows Apps + + https://developers.slashdot.org/story/20/09/23/1616231/google-expands-its-flutter-development-kit-to-windows-apps?utm_source=rss1.0mainlinkanon&utm_medium=feed + + Google has announced that Flutter, its open source UI development kit for + building cross-platform software from the same codebase, is finally available for + Windows apps in alpha. From a report:For the world's leading desktop operating system + with some 1 billion installations of Windows 10 alone, this has been a long time coming. + Flutter's alpha incarnation was initially launched at Google's I/O developer conference + back in 2017, before arriving in beta less than a year later. In its original guise, + Flutter was designed for Android and iOS app development, but it has since expanded to + cover the web, MacOS, and Linux, which are currently available in various alpha or beta + iterations. Developers have had to consider unique platform-specific factors when + designing for the desktop or mobile phones, such as different screen sizes and how + people interact with their devices. On smartphones, people typically use touch and + swipe-based gestures, while keyboards and mice are commonly used on PCs and laptops. + This means Flutter has had to expand its support to cover the additional inputs.<p><div + class="share_submission" style="position:relative;"> <a class="slashpop" + href="http://twitter.com/home?status=Google+Expands+its+Flutter+Development+Kit+To+Windows+Apps%3A+https%3A%2F%2Fbit.ly%2F32X36MW"><img + src="https://a.fsdn.com/sd/twitter_icon_large.png"></a> <a class="slashpop" + href="http://www.facebook.com/sharer.php?u=https%3A%2F%2Fdevelopers.slashdot.org%2Fstory%2F20%2F09%2F23%2F1616231%2Fgoogle-expands-its-flutter-development-kit-to-windows-apps%3Futm_source%3Dslashdot%26utm_medium%3Dfacebook"><img + src="https://a.fsdn.com/sd/facebook_icon_large.png"></a> + + + </div></p><p><a + href="https://developers.slashdot.org/story/20/09/23/1616231/google-expands-its-flutter-development-kit-to-windows-apps?utm_source=rss1.0moreanon&amp;utm_medium=feed">Read + more of this story</a> at Slashdot.</p><iframe + src="https://slashdot.org/slashdot-it.pl?op=discuss&amp;id=17251868&amp;smallembed=1" + style="height: 300px; width: 100%; border: none;"></iframe> + + msmash + programming + how-about-that + developers + 1 + 1,1,1,1,0,0,0 + + \ No newline at end of file diff --git a/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_link.xml b/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_link.xml new file mode 100644 index 00000000..b927c248 --- /dev/null +++ b/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_link.xml @@ -0,0 +1,40 @@ + + + Google Expands its Flutter Development Kit To Windows Apps + Google has announced that Flutter, its open source UI development kit for + building cross-platform software from the same codebase, is finally available for + Windows apps in alpha. From a report:For the world's leading desktop operating system + with some 1 billion installations of Windows 10 alone, this has been a long time coming. + Flutter's alpha incarnation was initially launched at Google's I/O developer conference + back in 2017, before arriving in beta less than a year later. In its original guise, + Flutter was designed for Android and iOS app development, but it has since expanded to + cover the web, MacOS, and Linux, which are currently available in various alpha or beta + iterations. Developers have had to consider unique platform-specific factors when + designing for the desktop or mobile phones, such as different screen sizes and how + people interact with their devices. On smartphones, people typically use touch and + swipe-based gestures, while keyboards and mice are commonly used on PCs and laptops. + This means Flutter has had to expand its support to cover the additional inputs.<p><div + class="share_submission" style="position:relative;"> <a class="slashpop" + href="http://twitter.com/home?status=Google+Expands+its+Flutter+Development+Kit+To+Windows+Apps%3A+https%3A%2F%2Fbit.ly%2F32X36MW"><img + src="https://a.fsdn.com/sd/twitter_icon_large.png"></a> <a class="slashpop" + href="http://www.facebook.com/sharer.php?u=https%3A%2F%2Fdevelopers.slashdot.org%2Fstory%2F20%2F09%2F23%2F1616231%2Fgoogle-expands-its-flutter-development-kit-to-windows-apps%3Futm_source%3Dslashdot%26utm_medium%3Dfacebook"><img + src="https://a.fsdn.com/sd/facebook_icon_large.png"></a> + + + </div></p><p><a + href="https://developers.slashdot.org/story/20/09/23/1616231/google-expands-its-flutter-development-kit-to-windows-apps?utm_source=rss1.0moreanon&amp;utm_medium=feed">Read + more of this story</a> at Slashdot.</p><iframe + src="https://slashdot.org/slashdot-it.pl?op=discuss&amp;id=17251868&amp;smallembed=1" + style="height: 300px; width: 100%; border: none;"></iframe> + + msmash + 2020-09-23T16:15:00+00:00 + programming + how-about-that + developers + 1 + 1,1,1,1,0,0,0 + + \ No newline at end of file diff --git a/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_title.xml b/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_title.xml new file mode 100644 index 00000000..96e0c123 --- /dev/null +++ b/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_title.xml @@ -0,0 +1,43 @@ + + + + https://developers.slashdot.org/story/20/09/23/1616231/google-expands-its-flutter-development-kit-to-windows-apps?utm_source=rss1.0mainlinkanon&utm_medium=feed + + Google has announced that Flutter, its open source UI development kit for + building cross-platform software from the same codebase, is finally available for + Windows apps in alpha. From a report:For the world's leading desktop operating system + with some 1 billion installations of Windows 10 alone, this has been a long time coming. + Flutter's alpha incarnation was initially launched at Google's I/O developer conference + back in 2017, before arriving in beta less than a year later. In its original guise, + Flutter was designed for Android and iOS app development, but it has since expanded to + cover the web, MacOS, and Linux, which are currently available in various alpha or beta + iterations. Developers have had to consider unique platform-specific factors when + designing for the desktop or mobile phones, such as different screen sizes and how + people interact with their devices. On smartphones, people typically use touch and + swipe-based gestures, while keyboards and mice are commonly used on PCs and laptops. + This means Flutter has had to expand its support to cover the additional inputs.<p><div + class="share_submission" style="position:relative;"> <a class="slashpop" + href="http://twitter.com/home?status=Google+Expands+its+Flutter+Development+Kit+To+Windows+Apps%3A+https%3A%2F%2Fbit.ly%2F32X36MW"><img + src="https://a.fsdn.com/sd/twitter_icon_large.png"></a> <a class="slashpop" + href="http://www.facebook.com/sharer.php?u=https%3A%2F%2Fdevelopers.slashdot.org%2Fstory%2F20%2F09%2F23%2F1616231%2Fgoogle-expands-its-flutter-development-kit-to-windows-apps%3Futm_source%3Dslashdot%26utm_medium%3Dfacebook"><img + src="https://a.fsdn.com/sd/facebook_icon_large.png"></a> + + + </div></p><p><a + href="https://developers.slashdot.org/story/20/09/23/1616231/google-expands-its-flutter-development-kit-to-windows-apps?utm_source=rss1.0moreanon&amp;utm_medium=feed">Read + more of this story</a> at Slashdot.</p><iframe + src="https://slashdot.org/slashdot-it.pl?op=discuss&amp;id=17251868&amp;smallembed=1" + style="height: 300px; width: 100%; border: none;"></iframe> + + msmash + 2020-09-23T16:15:00+00:00 + programming + how-about-that + developers + 1 + 1,1,1,1,0,0,0 + + \ No newline at end of file diff --git a/api/src/androidTest/assets/localfeed/rss1/rss1_items_special_cases.xml b/api/src/androidTest/assets/localfeed/rss1/rss1_items_special_cases.xml new file mode 100644 index 00000000..2624009b --- /dev/null +++ b/api/src/androidTest/assets/localfeed/rss1/rss1_items_special_cases.xml @@ -0,0 +1,120 @@ + + + + Slashdot + https://slashdot.org/ + News for nerds, stuff that matters + en-us + Copyright 1997-2016, SlashdotMedia. All Rights Reserved. + 2020-09-23T16:20:20+00:00 + Dice + help@slashdot.org + Technology + 1970-01-01T00:00+00:00 + 1 + hourly + + + + + + + + + + + + + + + + + + + + + + + + + + + Slashdot + https://a.fsdn.com/sd/topics/topicslashdot.gif + https://slashdot.org/ + + + A New York Clock That Told Time Now Tells the Time Remaining + For more than 20 years, Metronome, which includes a 62-foot-wide 15-digit + electronic clock that faces Union Square in Manhattan, has been one of the city's most + prominent and baffling public art projects. Its digital display once told the time in + its own unique way, counting the hours, minutes and seconds (and fractions thereof) to + and from midnight. But for years observers who did not understand how it worked + suggested that it was measuring the acres of rainforest destroyed each year, tracking + the world population or even that it had something to do with pi. On Saturday Metronome + adopted a new ecologically sensitive mission. From a report: Now, instead of measuring + 24-hour cycles, it is measuring what two artists, Gan Golan and Andrew Boyd, present as + a critical window for action to prevent the effects of global warming from becoming + irreversible. On Saturday at 3:20 p.m., messages including "The Earth has a deadline" + began to appear on the display. Then numbers -- 7:103:15:40:07 -- showed up, + representing the years, days, hours, minutes and seconds until that deadline. As a + handful of supporters watched, the number -- which the artists said was based on + calculations by the Mercator Research Institute on Global Commons and Climate Change in + Berlin -- began ticking down, second by second. + + "This is our way to shout that number from the rooftops." Mr. Golan said just before the + countdown began. "The world is literally counting on us." The Climate Clock, as the two + artists call their project, will be displayed on the 14th Street building, One Union + Square South, through Sept. 27, the end of Climate Week. The creators say their aim is + to arrange for the clock to be permanently displayed, there or elsewhere. Mr. Golan said + he came up with the idea to publicly illustrate the urgency of combating climate change + about two years ago, shortly after his daughter was born. He asked Mr. Boyd, an activist + from the Lower East Side, to work with him on the project.<p><div + class="share_submission" style="position:relative;"> <a class="slashpop" + href="http://twitter.com/home?status=A+New+York+Clock+That+Told+Time+Now+Tells+the+Time+Remaining%3A+https%3A%2F%2Fbit.ly%2F2HrAt2b"><img + src="https://a.fsdn.com/sd/twitter_icon_large.png"></a> <a class="slashpop" + href="http://www.facebook.com/sharer.php?u=https%3A%2F%2Fnews.slashdot.org%2Fstory%2F20%2F09%2F23%2F1420240%2Fa-new-york-clock-that-told-time-now-tells-the-time-remaining%3Futm_source%3Dslashdot%26utm_medium%3Dfacebook"><img + src="https://a.fsdn.com/sd/facebook_icon_large.png"></a> + + + </div></p><p><a + href="https://news.slashdot.org/story/20/09/23/1420240/a-new-york-clock-that-told-time-now-tells-the-time-remaining?utm_source=rss1.0moreanon&amp;utm_medium=feed">Read + more of this story</a> at Slashdot.</p><iframe + src="https://slashdot.org/slashdot-it.pl?op=discuss&amp;id=17251272&amp;smallembed=1" + style="height: 300px; width: 100%; border: none;"></iframe> + + msmash + + creator 2 + creator 3 + creator 4 + creator 5 + 2020-09-23T14:10:00+00:00 + news + how-about-that + news + 43 + 43,38,33,27,6,1,0 + + \ No newline at end of file diff --git a/api/src/androidTest/java/com/readrops/api/localfeed/rss1/RSS1ItemsAdapterTest.kt b/api/src/androidTest/java/com/readrops/api/localfeed/rss1/RSS1ItemsAdapterTest.kt new file mode 100644 index 00000000..178220da --- /dev/null +++ b/api/src/androidTest/java/com/readrops/api/localfeed/rss1/RSS1ItemsAdapterTest.kt @@ -0,0 +1,70 @@ +package com.readrops.api.localfeed.rss1 + +import android.content.Context +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import com.readrops.api.utils.DateUtils +import com.readrops.api.utils.ParseException +import junit.framework.TestCase.assertEquals +import junit.framework.TestCase.assertNotNull +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class RSS1ItemsAdapterTest { + + private val context: Context = InstrumentationRegistry.getInstrumentation().context + + private val adapter = RSS1ItemsAdapter() + + @Test + fun normalCasesTest() { + val stream = context.resources.assets.open("localfeed/rss1/rss1_feed.xml") + + val items = adapter.fromXml(stream) + val item = items.first() + + assertEquals(items.size, 4) + assertEquals(item.title, "Google Expands its Flutter Development Kit To Windows Apps") + assertEquals(item.link.trim(), "https://developers.slashdot.org/story/20/09/23/1616231/google-expands-" + + "its-flutter-development-kit-to-windows-apps?utm_source=rss1.0mainlinkanon&utm_medium=feed") + assertEquals(item.guid.trim(), "https://developers.slashdot.org/story/20/09/23/1616231/google-expands-" + + "its-flutter-development-kit-to-windows-apps?utm_source=rss1.0mainlinkanon&utm_medium=feed") + assertEquals(item.pubDate, DateUtils.stringToLocalDateTime("2020-09-23T16:15:00+00:00")) + assertEquals(item.author, "msmash") + assertNotNull(item.description) + } + + @Test + fun specialCasesTest() { + val stream = context.resources.assets.open("localfeed/rss1/rss1_items_special_cases.xml") + + val item = adapter.fromXml(stream).first() + + assertEquals(item.author, "msmash, creator 2, creator 3, creator 4, ...") + assertEquals(item.link, "https://news.slashdot.org/story/20/09/23/1420240/a-new-york-clock-" + + "that-told-time-now-tells-the-time-remaining?utm_source=rss1.0mainlinkanon&utm_medium=feed") + } + + @Test + fun nullTitleTest() { + val stream = context.resources.assets.open("localfeed/rss1/rss1_items_no_title.xml") + + Assert.assertThrows(ParseException::class.java) { adapter.fromXml(stream) } + } + + @Test + fun nullLinkTest() { + val stream = context.resources.assets.open("localfeed/rss1/rss1_items_no_link.xml") + + Assert.assertThrows(ParseException::class.java) { adapter.fromXml(stream) } + } + + @Test + fun nullDateTest() { + val stream = context.resources.assets.open("localfeed/rss1/rss1_items_no_date.xml") + + Assert.assertThrows(ParseException::class.java) { adapter.fromXml(stream) } + } +} \ No newline at end of file diff --git a/api/src/main/java/com/readrops/api/localfeed/XmlAdapter.kt b/api/src/main/java/com/readrops/api/localfeed/XmlAdapter.kt index 1641c00f..91807c54 100644 --- a/api/src/main/java/com/readrops/api/localfeed/XmlAdapter.kt +++ b/api/src/main/java/com/readrops/api/localfeed/XmlAdapter.kt @@ -3,6 +3,7 @@ package com.readrops.api.localfeed import com.readrops.api.localfeed.atom.ATOMFeedAdapter import com.readrops.api.localfeed.atom.ATOMItemsAdapter import com.readrops.api.localfeed.rss1.RSS1FeedAdapter +import com.readrops.api.localfeed.rss1.RSS1ItemsAdapter import com.readrops.api.localfeed.rss2.RSS2FeedAdapter import com.readrops.api.localfeed.rss2.RSS2ItemsAdapter import com.readrops.db.entities.Feed @@ -25,6 +26,7 @@ interface XmlAdapter { fun xmlItemsAdapterFactory(type: LocalRSSHelper.RSSType): XmlAdapter> { return when (type) { + LocalRSSHelper.RSSType.RSS_1 -> RSS1ItemsAdapter() LocalRSSHelper.RSSType.RSS_2 -> RSS2ItemsAdapter() LocalRSSHelper.RSSType.ATOM -> ATOMItemsAdapter() else -> throw IllegalArgumentException("Unknown RSS type : $type") diff --git a/api/src/main/java/com/readrops/api/localfeed/rss1/RSS1ItemsAdapter.kt b/api/src/main/java/com/readrops/api/localfeed/rss1/RSS1ItemsAdapter.kt new file mode 100644 index 00000000..26b6e239 --- /dev/null +++ b/api/src/main/java/com/readrops/api/localfeed/rss1/RSS1ItemsAdapter.kt @@ -0,0 +1,68 @@ +package com.readrops.api.localfeed.rss1 + +import com.gitlab.mvysny.konsumexml.Names +import com.gitlab.mvysny.konsumexml.allChildrenAutoIgnore +import com.gitlab.mvysny.konsumexml.konsumeXml +import com.readrops.api.localfeed.XmlAdapter +import com.readrops.api.utils.DateUtils +import com.readrops.api.utils.ParseException +import com.readrops.api.utils.nonNullText +import com.readrops.api.utils.nullableText +import com.readrops.db.entities.Item +import java.io.InputStream + +class RSS1ItemsAdapter : XmlAdapter> { + + override fun fromXml(inputStream: InputStream): List { + val konsume = inputStream.konsumeXml() + val items = arrayListOf() + + return try { + konsume.child("RDF") { + allChildrenAutoIgnore("item") { + val authors = arrayListOf() + val about = attributes.getValueOpt("about", + namespace = "http://www.w3.org/1999/02/22-rdf-syntax-ns#") + + val item = Item().apply { + allChildrenAutoIgnore(names) { + when (tagName) { + "title" -> title = nonNullText() + "link" -> link = nullableText() + "dc:date" -> pubDate = DateUtils.stringToLocalDateTime(nonNullText()) + "dc:creator" -> authors += nullableText() + "description" -> description = nullableText(failOnElement = false) + else -> skipContents() + } + } + } + + item.guid = item.link + if (authors.filterNotNull().isNotEmpty()) item.author = authors.filterNotNull().joinToString(limit = 4) + if (item.link == null) item.link = about + + validateItem(item) + + items += item + } + } + + konsume.close() + items + } catch (e: Exception) { + throw ParseException(e.message) + } + } + + private fun validateItem(item: Item) { + when { + item.title == null -> throw ParseException("Item title is required") + item.link == null -> throw ParseException("Item link is required") + item.pubDate == null -> throw ParseException("Item date is required") + } + } + + companion object { + val names = Names.of("title", "description", "date", "link", "creator") + } +} \ No newline at end of file diff --git a/api/src/test/java/com/readrops/api/localfeed/XmlAdapterTest.kt b/api/src/test/java/com/readrops/api/localfeed/XmlAdapterTest.kt index 47df7eb9..64e73791 100644 --- a/api/src/test/java/com/readrops/api/localfeed/XmlAdapterTest.kt +++ b/api/src/test/java/com/readrops/api/localfeed/XmlAdapterTest.kt @@ -3,6 +3,7 @@ package com.readrops.api.localfeed import com.readrops.api.localfeed.atom.ATOMFeedAdapter import com.readrops.api.localfeed.atom.ATOMItemsAdapter import com.readrops.api.localfeed.rss1.RSS1FeedAdapter +import com.readrops.api.localfeed.rss1.RSS1ItemsAdapter import com.readrops.api.localfeed.rss2.RSS2FeedAdapter import com.readrops.api.localfeed.rss2.RSS2ItemsAdapter import junit.framework.TestCase.assertTrue @@ -22,6 +23,7 @@ class XmlAdapterTest { @Test fun xmlItemsAdapterFactoryTest() { + assertTrue(XmlAdapter.xmlItemsAdapterFactory(LocalRSSHelper.RSSType.RSS_1) is RSS1ItemsAdapter) assertTrue(XmlAdapter.xmlItemsAdapterFactory(LocalRSSHelper.RSSType.RSS_2) is RSS2ItemsAdapter) assertTrue(XmlAdapter.xmlItemsAdapterFactory(LocalRSSHelper.RSSType.ATOM) is ATOMItemsAdapter)