Просмотр исходного кода

refactor null safety migration

master
Wito Chandra 5 лет назад
Родитель
Сommit
648f324981
47 измененных файлов: 387 добавлений и 357 удалений
  1. +8
    -4
      example/main.dart
  2. +14
    -11
      lib/domain/atom_feed.dart
  3. +1
    -2
      lib/domain/atom_generator.dart
  4. +12
    -9
      lib/domain/atom_item.dart
  5. +4
    -4
      lib/domain/atom_person.dart
  6. +5
    -6
      lib/domain/atom_source.dart
  7. +21
    -22
      lib/domain/dublin_core/dublin_core.dart
  8. +38
    -25
      lib/domain/itunes/itunes.dart
  9. +3
    -4
      lib/domain/itunes/itunes_category.dart
  10. +2
    -2
      lib/domain/itunes/itunes_episode_type.dart
  11. +2
    -6
      lib/domain/itunes/itunes_image.dart
  12. +4
    -4
      lib/domain/itunes/itunes_owner.dart
  13. +2
    -2
      lib/domain/itunes/itunes_type.dart
  14. +1
    -2
      lib/domain/media/category.dart
  15. +14
    -12
      lib/domain/media/community.dart
  16. +1
    -2
      lib/domain/media/copyright.dart
  17. +1
    -2
      lib/domain/media/description.dart
  18. +6
    -6
      lib/domain/media/embed.dart
  19. +18
    -15
      lib/domain/media/group.dart
  20. +1
    -2
      lib/domain/media/hash.dart
  21. +1
    -2
      lib/domain/media/license.dart
  22. +102
    -78
      lib/domain/media/media.dart
  23. +1
    -2
      lib/domain/media/param.dart
  24. +1
    -2
      lib/domain/media/peer_link.dart
  25. +1
    -2
      lib/domain/media/player.dart
  26. +1
    -2
      lib/domain/media/rating.dart
  27. +1
    -2
      lib/domain/media/restriction.dart
  28. +1
    -2
      lib/domain/media/rights.dart
  29. +6
    -7
      lib/domain/media/scene.dart
  30. +1
    -2
      lib/domain/media/status.dart
  31. +1
    -2
      lib/domain/media/tags.dart
  32. +1
    -2
      lib/domain/media/text.dart
  33. +1
    -2
      lib/domain/media/title.dart
  34. +1
    -2
      lib/domain/rss_category.dart
  35. +1
    -2
      lib/domain/rss_cloud.dart
  36. +4
    -7
      lib/domain/rss_content.dart
  37. +1
    -2
      lib/domain/rss_enclosure.dart
  38. +38
    -26
      lib/domain/rss_feed.dart
  39. +5
    -6
      lib/domain/rss_image.dart
  40. +21
    -12
      lib/domain/rss_item.dart
  41. +1
    -2
      lib/domain/rss_source.dart
  42. +6
    -7
      lib/domain/syndication/syndication.dart
  43. +0
    -0
      lib/util/function.dart
  44. +3
    -0
      lib/util/iterable.dart
  45. +2
    -15
      lib/util/xml.dart
  46. +9
    -9
      test/atom_test.dart
  47. +18
    -18
      test/rss_test.dart

+ 8
- 4
example/main.dart Просмотреть файл

@@ -1,18 +1,22 @@
import 'package:http/http.dart' as http;
import 'dart:io';

import 'package:http/io_client.dart';
import 'package:webfeed/webfeed.dart';

void main() async {
var client = http.Client();
final client = IOClient(HttpClient()
..badCertificateCallback =
((X509Certificate cert, String host, int port) => true));

// RSS feed
var response = await client.get(
Uri(path: 'https://developer.apple.com/news/releases/rss/releases.rss'));
Uri.parse('https://developer.apple.com/news/releases/rss/releases.rss'));
var channel = RssFeed.parse(response.body);
print(channel);

// Atom feed
response =
await client.get(Uri(path: 'https://www.theverge.com/rss/index.xml'));
await client.get(Uri.parse('https://www.theverge.com/rss/index.xml'));
var feed = AtomFeed.parse(response.body);
print(feed);



+ 14
- 11
lib/domain/atom_feed.dart Просмотреть файл

@@ -4,7 +4,7 @@ import 'package:webfeed/domain/atom_item.dart';
import 'package:webfeed/domain/atom_link.dart';
import 'package:webfeed/domain/atom_person.dart';
import 'package:webfeed/util/datetime.dart';
import 'package:webfeed/util/xml.dart';
import 'package:webfeed/util/iterable.dart';
import 'package:xml/xml.dart';

class AtomFeed {
@@ -41,15 +41,16 @@ class AtomFeed {

factory AtomFeed.parse(String xmlString) {
var document = XmlDocument.parse(xmlString);
var feedElement = findFirstElement(document, 'feed');
var feedElement = document.findElements('feed').firstOrNull;
if (feedElement == null) {
throw ArgumentError('feed not found');
}

return AtomFeed(
id: findFirstElement(feedElement, 'id')?.text,
title: findFirstElement(feedElement, 'title')?.text,
updated: parseDateTime(findFirstElement(feedElement, 'updated')?.text),
id: feedElement.findElements('id').firstOrNull?.text,
title: feedElement.findElements('title').firstOrNull?.text,
updated:
parseDateTime(feedElement.findElements('updated').firstOrNull?.text),
items: feedElement
.findElements('entry')
.map((e) => AtomItem.parse(e))
@@ -70,12 +71,14 @@ class AtomFeed {
.findElements('category')
.map((e) => AtomCategory.parse(e))
.toList(),
generator:
AtomGenerator.parse(findFirstElement(feedElement, 'generator')),
icon: findFirstElement(feedElement, 'icon')?.text,
logo: findFirstElement(feedElement, 'logo')?.text,
rights: findFirstElement(feedElement, 'rights')?.text,
subtitle: findFirstElement(feedElement, 'subtitle')?.text,
generator: feedElement
.findElements('generator')
.map((e) => AtomGenerator.parse(e))
.firstOrNull,
icon: feedElement.findElements('icon').firstOrNull?.text,
logo: feedElement.findElements('logo').firstOrNull?.text,
rights: feedElement.findElements('rights').firstOrNull?.text,
subtitle: feedElement.findElements('subtitle').firstOrNull?.text,
);
}
}

+ 1
- 2
lib/domain/atom_generator.dart Просмотреть файл

@@ -7,8 +7,7 @@ class AtomGenerator {

AtomGenerator(this.uri, this.version, this.value);

static parse(XmlElement? element) {
if (element == null) return null;
factory AtomGenerator.parse(XmlElement element) {
var uri = element.getAttribute('uri');
var version = element.getAttribute('version');
var value = element.text;


+ 12
- 9
lib/domain/atom_item.dart Просмотреть файл

@@ -4,7 +4,7 @@ import 'package:webfeed/domain/atom_person.dart';
import 'package:webfeed/domain/atom_source.dart';
import 'package:webfeed/domain/media/media.dart';
import 'package:webfeed/util/datetime.dart';
import 'package:webfeed/util/xml.dart';
import 'package:webfeed/util/iterable.dart';
import 'package:xml/xml.dart';

class AtomItem {
@@ -41,9 +41,9 @@ class AtomItem {

factory AtomItem.parse(XmlElement element) {
return AtomItem(
id: findFirstElement(element, 'id')?.text,
title: findFirstElement(element, 'title')?.text,
updated: parseDateTime(findFirstElement(element, 'updated')?.text),
id: element.findElements('id').firstOrNull?.text,
title: element.findElements('title').firstOrNull?.text,
updated: parseDateTime(element.findElements('updated').firstOrNull?.text),
authors: element
.findElements('author')
.map((e) => AtomPerson.parse(e))
@@ -58,11 +58,14 @@ class AtomItem {
.findElements('contributor')
.map((e) => AtomPerson.parse(e))
.toList(),
source: AtomSource.parse(findFirstElement(element, 'source')),
published: findFirstElement(element, 'published')?.text,
content: findFirstElement(element, 'content')?.text,
summary: findFirstElement(element, 'summary')?.text,
rights: findFirstElement(element, 'rights')?.text,
source: element
.findElements('source')
.map((e) => AtomSource.parse(e))
.firstOrNull,
published: element.findElements('published').firstOrNull?.text,
content: element.findElements('content').firstOrNull?.text,
summary: element.findElements('summary').firstOrNull?.text,
rights: element.findElements('rights').firstOrNull?.text,
media: Media.parse(element),
);
}


+ 4
- 4
lib/domain/atom_person.dart Просмотреть файл

@@ -1,4 +1,4 @@
import 'package:webfeed/util/xml.dart';
import 'package:webfeed/util/iterable.dart';
import 'package:xml/xml.dart';

class AtomPerson {
@@ -10,9 +10,9 @@ class AtomPerson {

factory AtomPerson.parse(XmlElement element) {
return AtomPerson(
name: findFirstElement(element, 'name')?.text,
uri: findFirstElement(element, 'uri')?.text,
email: findFirstElement(element, 'email')?.text,
name: element.findElements('name').firstOrNull?.text,
uri: element.findElements('uri').firstOrNull?.text,
email: element.findElements('email').firstOrNull?.text,
);
}
}

+ 5
- 6
lib/domain/atom_source.dart Просмотреть файл

@@ -1,4 +1,4 @@
import 'package:webfeed/util/xml.dart';
import 'package:webfeed/util/iterable.dart';
import 'package:xml/xml.dart';

class AtomSource {
@@ -12,12 +12,11 @@ class AtomSource {
this.updated,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory AtomSource.parse(XmlElement element) {
return AtomSource(
id: findFirstElement(element, 'id')?.text,
title: findFirstElement(element, 'title')?.text,
updated: findFirstElement(element, 'updated')?.text,
id: element.findElements('id').firstOrNull?.text,
title: element.findElements('title').firstOrNull?.text,
updated: element.findElements('updated').firstOrNull?.text,
);
}
}

+ 21
- 22
lib/domain/dublin_core/dublin_core.dart Просмотреть файл

@@ -1,5 +1,5 @@
import 'package:webfeed/util/datetime.dart';
import 'package:webfeed/util/xml.dart';
import 'package:webfeed/util/iterable.dart';
import 'package:xml/xml.dart';

class DublinCore {
@@ -41,28 +41,27 @@ class DublinCore {
this.rights,
});

static parse(XmlElement? element) {
if (element == null) {
return null;
}
factory DublinCore.parse(XmlElement element) {
return DublinCore(
title: findFirstElement(element, 'dc:title')?.text,
description: findFirstElement(element, 'dc:description')?.text,
creator: findFirstElement(element, 'dc:creator')?.text,
subject: findFirstElement(element, 'dc:subject')?.text,
publisher: findFirstElement(element, 'dc:publisher')?.text,
contributor: findFirstElement(element, 'dc:contributor')?.text,
date: parseDateTime(findFirstElement(element, 'dc:date')?.text),
created: parseDateTime(findFirstElement(element, 'dc:created')?.text),
modified: parseDateTime(findFirstElement(element, 'dc:modified')?.text),
type: findFirstElement(element, 'dc:type')?.text,
format: findFirstElement(element, 'dc:format')?.text,
identifier: findFirstElement(element, 'dc:identifier')?.text,
source: findFirstElement(element, 'dc:source')?.text,
language: findFirstElement(element, 'dc:language')?.text,
relation: findFirstElement(element, 'dc:relation')?.text,
coverage: findFirstElement(element, 'dc:coverage')?.text,
rights: findFirstElement(element, 'dc:rights')?.text,
title: element.findElements('dc:title').firstOrNull?.text,
description: element.findElements('dc:description').firstOrNull?.text,
creator: element.findElements('dc:creator').firstOrNull?.text,
subject: element.findElements('dc:subject').firstOrNull?.text,
publisher: element.findElements('dc:publisher').firstOrNull?.text,
contributor: element.findElements('dc:contributor').firstOrNull?.text,
date: parseDateTime(element.findElements('dc:date').firstOrNull?.text),
created:
parseDateTime(element.findElements('dc:created').firstOrNull?.text),
modified:
parseDateTime(element.findElements('dc:modified').firstOrNull?.text),
type: element.findElements('dc:type').firstOrNull?.text,
format: element.findElements('dc:format').firstOrNull?.text,
identifier: element.findElements('dc:identifier').firstOrNull?.text,
source: element.findElements('dc:source').firstOrNull?.text,
language: element.findElements('dc:language').firstOrNull?.text,
relation: element.findElements('dc:relation').firstOrNull?.text,
coverage: element.findElements('dc:coverage').firstOrNull?.text,
rights: element.findElements('dc:rights').firstOrNull?.text,
);
}
}

+ 38
- 25
lib/domain/itunes/itunes.dart Просмотреть файл

@@ -3,6 +3,7 @@ import 'package:webfeed/domain/itunes/itunes_episode_type.dart';
import 'package:webfeed/domain/itunes/itunes_image.dart';
import 'package:webfeed/domain/itunes/itunes_owner.dart';
import 'package:webfeed/domain/itunes/itunes_type.dart';
import 'package:webfeed/util/iterable.dart';
import 'package:webfeed/util/xml.dart';
import 'package:xml/xml.dart';

@@ -15,7 +16,7 @@ class Itunes {
final ItunesOwner? owner;
final List<String>? keywords;
final ItunesImage? image;
final List<ItunesCategory?>? categories;
final List<ItunesCategory>? categories;
final ItunesType? type;
final String? newFeedUrl;
final bool? block;
@@ -45,39 +46,51 @@ class Itunes {
this.episodeType,
});

static parse(XmlElement? element) {
if (element == null) {
return null;
}
var episodeStr = findFirstElement(element, 'itunes:episode')?.text;
var seasonStr = findFirstElement(element, 'itunes:season')?.text;
var durationStr = findFirstElement(element, 'itunes:duration')?.text;
factory Itunes.parse(XmlElement element) {
final episodeStr = element.findElements('itunes:episode').firstOrNull?.text;
final seasonStr = element.findElements('itunes:season').firstOrNull?.text;
final durationStr =
element.findElements('itunes:duration').firstOrNull?.text;
return Itunes(
author: findFirstElement(element, 'itunes:author')?.text,
summary: findFirstElement(element, 'itunes:summary')?.text,
author: element.findElements('itunes:author').firstOrNull?.text,
summary: element.findElements('itunes:summary').firstOrNull?.text,
explicit: parseBoolLiteral(element, 'itunes:explicit'),
title: findFirstElement(element, 'itunes:title')?.text,
subtitle: findFirstElement(element, 'itunes:subtitle')?.text,
owner: ItunesOwner.parse(findFirstElement(element, 'itunes:owner')),
keywords: findFirstElement(element, 'itunes:keywords')
title: element.findElements('itunes:title').firstOrNull?.text,
subtitle: element.findElements('itunes:subtitle').firstOrNull?.text,
owner: element
.findElements('itunes:owner')
.map((e) => ItunesOwner.parse(e))
.firstOrNull,
keywords: element
.findElements('itunes:keywords')
.firstOrNull
?.text
.split(',')
.map((keyword) => keyword.trim())
.toList() ??
[],
image: ItunesImage.parse(findFirstElement(element, 'itunes:image')),
categories: findElements(element, 'itunes:category')!
image: element
.findElements('itunes:image')
.map((e) => ItunesImage.parse(e))
.firstOrNull,
categories: element
.findElements('itunes:category')
.map((e) => ItunesCategory.parse(e))
.toList(),
type: newItunesType(findFirstElement(element, 'itunes:type')),
newFeedUrl: findFirstElement(element, 'itunes:new-feed-url')?.text,
type: element
.findElements('itunes:type')
.map((e) => newItunesType(e))
.firstOrNull,
newFeedUrl: element.findElements('itunes:new-feed-url').firstOrNull?.text,
block: parseBoolLiteral(element, 'itunes:block'),
complete: parseBoolLiteral(element, 'itunes:complete'),
episode: episodeStr == null ? null : int.parse(episodeStr),
season: seasonStr == null ? null : int.parse(seasonStr),
episode: episodeStr == null ? null : int.tryParse(episodeStr),
season: seasonStr == null ? null : int.tryParse(seasonStr),
duration: durationStr == null ? null : _parseDuration(durationStr),
episodeType:
newItunesEpisodeType(findFirstElement(element, 'itunes:episodeType')),
episodeType: element
.findElements('itunes:episodeType')
.map((e) => newItunesEpisodeType(e))
.firstOrNull,
);
}

@@ -87,12 +100,12 @@ class Itunes {
var seconds = 0;
var parts = s.split(':');
if (parts.length > 2) {
hours = int.parse(parts[parts.length - 3]);
hours = int.tryParse(parts[parts.length - 3]) ?? 0;
}
if (parts.length > 1) {
minutes = int.parse(parts[parts.length - 2]);
minutes = int.tryParse(parts[parts.length - 2]) ?? 0;
}
seconds = int.parse(parts[parts.length - 1]);
seconds = int.tryParse(parts[parts.length - 1]) ?? 0;
return Duration(
hours: hours,
minutes: minutes,


+ 3
- 4
lib/domain/itunes/itunes_category.dart Просмотреть файл

@@ -2,17 +2,16 @@ import 'package:xml/xml.dart';

class ItunesCategory {
final String? category;
final List<String?>? subCategories;
final List<String>? subCategories;

ItunesCategory({this.category, this.subCategories});

static ItunesCategory? parse(XmlElement? element) {
if (element == null) return null;
factory ItunesCategory.parse(XmlElement element) {
return ItunesCategory(
category: element.getAttribute('text')?.trim(),
subCategories: element
.findElements('itunes:category')
.map((e) => e.getAttribute('text')?.trim())
.map((e) => e.getAttribute('text')?.trim() ?? '')
.toList());
}
}

+ 2
- 2
lib/domain/itunes/itunes_episode_type.dart Просмотреть файл

@@ -2,8 +2,8 @@ import 'package:xml/xml.dart';

enum ItunesEpisodeType { full, trailer, bonus, unknown }

ItunesEpisodeType newItunesEpisodeType(XmlElement? element) {
switch (element?.text) {
ItunesEpisodeType newItunesEpisodeType(XmlElement element) {
switch (element.text) {
case 'full':
return ItunesEpisodeType.full;
case 'trailer':


+ 2
- 6
lib/domain/itunes/itunes_image.dart Просмотреть файл

@@ -5,13 +5,9 @@ class ItunesImage {

ItunesImage({this.href});

static parse(XmlElement? element) {
ItunesImage? result;
if (element == null) return null;
result = ItunesImage(
factory ItunesImage.parse(XmlElement element) {
return ItunesImage(
href: element.getAttribute('href')?.trim(),
);

return result;
}
}

+ 4
- 4
lib/domain/itunes/itunes_owner.dart Просмотреть файл

@@ -1,4 +1,4 @@
import 'package:webfeed/util/xml.dart';
import 'package:webfeed/util/iterable.dart';
import 'package:xml/xml.dart';

class ItunesOwner {
@@ -7,10 +7,10 @@ class ItunesOwner {

ItunesOwner({this.name, this.email});

factory ItunesOwner.parse(XmlElement? element) {
factory ItunesOwner.parse(XmlElement element) {
return ItunesOwner(
name: findFirstElement(element, 'itunes:name')?.text.trim(),
email: findFirstElement(element, 'itunes:email')?.text.trim(),
name: element.findElements('itunes:name').firstOrNull?.text.trim(),
email: element.findElements('itunes:email').firstOrNull?.text.trim(),
);
}
}

+ 2
- 2
lib/domain/itunes/itunes_type.dart Просмотреть файл

@@ -2,8 +2,8 @@ import 'package:xml/xml.dart';

enum ItunesType { episodic, serial, unknown }

ItunesType newItunesType(XmlElement? element) {
switch (element?.text) {
ItunesType newItunesType(XmlElement element) {
switch (element.text) {
case 'episodic':
return ItunesType.episodic;
case 'serial':


+ 1
- 2
lib/domain/media/category.dart Просмотреть файл

@@ -11,8 +11,7 @@ class Category {
this.value,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory Category.parse(XmlElement element) {
return Category(
scheme: element.getAttribute('scheme'),
label: element.getAttribute('label'),


+ 14
- 12
lib/domain/media/community.dart Просмотреть файл

@@ -1,7 +1,7 @@
import 'package:webfeed/domain/media/star_rating.dart';
import 'package:webfeed/domain/media/statistics.dart';
import 'package:webfeed/domain/media/tags.dart';
import 'package:webfeed/util/xml.dart';
import 'package:webfeed/util/iterable.dart';
import 'package:xml/xml.dart';

class Community {
@@ -15,18 +15,20 @@ class Community {
this.tags,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory Community.parse(XmlElement element) {
return Community(
starRating: StarRating.parse(
findFirstElement(element, 'media:starRating'),
),
statistics: Statistics.parse(
findFirstElement(element, 'media:statistics'),
),
tags: Tags.parse(
findFirstElement(element, 'media:tags'),
),
starRating: element
.findElements('media:starRating')
.map((e) => StarRating.parse(e))
.firstOrNull,
statistics: element
.findElements('media:statistics')
.map((e) => Statistics.parse(e))
.firstOrNull,
tags: element
.findElements('media:tags')
.map((e) => Tags.parse(e))
.firstOrNull,
);
}
}

+ 1
- 2
lib/domain/media/copyright.dart Просмотреть файл

@@ -9,8 +9,7 @@ class Copyright {
this.value,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory Copyright.parse(XmlElement element) {
return Copyright(
url: element.getAttribute('url'),
value: element.text,


+ 1
- 2
lib/domain/media/description.dart Просмотреть файл

@@ -9,8 +9,7 @@ class Description {
this.value,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory Description.parse(XmlElement element) {
return Description(
type: element.getAttribute('type'),
value: element.text,


+ 6
- 6
lib/domain/media/embed.dart Просмотреть файл

@@ -5,7 +5,7 @@ class Embed {
final String? url;
final int? width;
final int? height;
final List<Param?>? params;
final List<Param>? params;

Embed({
this.url,
@@ -14,15 +14,15 @@ class Embed {
this.params,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory Embed.parse(XmlElement element) {
return Embed(
url: element.getAttribute('url'),
width: int.tryParse(element.getAttribute('width') ?? '0'),
height: int.tryParse(element.getAttribute('height') ?? '0'),
params: element.findElements('media:param').map((e) {
return Param.parse(e);
}).toList(),
params: element
.findElements('media:param')
.map((e) => Param.parse(e))
.toList(),
);
}
}

+ 18
- 15
lib/domain/media/group.dart Просмотреть файл

@@ -2,7 +2,7 @@ import 'package:webfeed/domain/media/category.dart';
import 'package:webfeed/domain/media/content.dart';
import 'package:webfeed/domain/media/credit.dart';
import 'package:webfeed/domain/media/rating.dart';
import 'package:webfeed/util/xml.dart';
import 'package:webfeed/util/iterable.dart';
import 'package:xml/xml.dart';

class Group {
@@ -18,21 +18,24 @@ class Group {
this.rating,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory Group.parse(XmlElement element) {
return Group(
contents: element.findElements('media:content').map((e) {
return Content.parse(e);
}).toList(),
credits: element.findElements('media:credit').map((e) {
return Credit.parse(e);
}).toList(),
category: Category.parse(
findFirstElement(element, 'media:category'),
),
rating: Rating.parse(
findFirstElement(element, 'media:rating'),
),
contents: element
.findElements('media:content')
.map((e) => Content.parse(e))
.toList(),
credits: element
.findElements('media:credit')
.map((e) => Credit.parse(e))
.toList(),
category: element
.findElements('media:category')
.map((e) => Category.parse(e))
.firstOrNull,
rating: element
.findElements('media:rating')
.map((e) => Rating.parse(e))
.firstOrNull,
);
}
}

+ 1
- 2
lib/domain/media/hash.dart Просмотреть файл

@@ -9,8 +9,7 @@ class Hash {
this.value,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory Hash.parse(XmlElement element) {
return Hash(
algo: element.getAttribute('algo'),
value: element.text,


+ 1
- 2
lib/domain/media/license.dart Просмотреть файл

@@ -11,8 +11,7 @@ class License {
this.value,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory License.parse(XmlElement element) {
return License(
type: element.getAttribute('type'),
href: element.getAttribute('href'),


+ 102
- 78
lib/domain/media/media.dart Просмотреть файл

@@ -20,6 +20,7 @@ import 'package:webfeed/domain/media/text.dart';
import 'package:webfeed/domain/media/thumbnail.dart';
import 'package:webfeed/domain/media/title.dart';
import 'package:webfeed/util/xml.dart';
import 'package:webfeed/util/iterable.dart';
import 'package:xml/xml.dart';

class Media {
@@ -47,7 +48,7 @@ class Media {
final License? license;
final PeerLink? peerLink;
final Rights? rights;
final List<Scene?>? scenes;
final List<Scene>? scenes;

Media({
this.group,
@@ -79,90 +80,113 @@ class Media {

factory Media.parse(XmlElement element) {
return Media(
group: Group.parse(
findFirstElement(element, 'media:group'),
),
contents: element.findElements('media:content').map((e) {
return Content.parse(e);
}).toList(),
credits: element.findElements('media:credit').map((e) {
return Credit.parse(e);
}).toList(),
category: Category.parse(
findFirstElement(element, 'media:category'),
),
rating: Rating.parse(
findFirstElement(element, 'media:rating'),
),
title: Title.parse(
findFirstElement(element, 'media:title'),
),
description: Description.parse(
findFirstElement(element, 'media:description'),
),
keywords: findFirstElement(element, 'media:keywords')?.text,
thumbnails: element.findElements('media:thumbnail').map((e) {
return Thumbnail.parse(e);
}).toList(),
hash: Hash.parse(
findFirstElement(element, 'media:hash'),
),
player: Player.parse(
findFirstElement(element, 'media:player'),
),
copyright: Copyright.parse(
findFirstElement(element, 'media:copyright'),
),
text: Text.parse(
findFirstElement(element, 'media:text'),
),
restriction: Restriction.parse(
findFirstElement(element, 'media:restriction'),
),
community: Community.parse(
findFirstElement(element, 'media:community'),
),
comments: findFirstElement(element, 'media:comments')
group: element
.findElements('media:group')
.map((e) => Group.parse(e))
.firstOrNull,
contents: element
.findElements('media:content')
.map((e) => Content.parse(e))
.toList(),
credits: element
.findElements('media:credit')
.map((e) => Credit.parse(e))
.toList(),
category: element
.findElements('media:category')
.map((e) => Category.parse(e))
.firstOrNull,
rating: element
.findElements('media:rating')
.map((e) => Rating.parse(e))
.firstOrNull,
title: findElements(element, 'media:title')
?.map((e) => Title.parse(e))
.firstOrNull,
description: element
.findElements('media:description')
.map((e) => Description.parse(e))
.firstOrNull,
keywords: element.findElements('media:keywords').firstOrNull?.text,
thumbnails: element
.findElements('media:thumbnail')
.map((e) => Thumbnail.parse(e))
.toList(),
hash: element
.findElements('media:hash')
.map((e) => Hash.parse(e))
.firstOrNull,
player: element
.findElements('media:player')
.map((e) => Player.parse(e))
.firstOrNull,
copyright: element
.findElements('media:copyright')
.map((e) => Copyright.parse(e))
.firstOrNull,
text: element
.findElements('media:text')
.map((e) => Text.parse(e))
.firstOrNull,
restriction: element
.findElements('media:restriction')
.map((e) => Restriction.parse(e))
.firstOrNull,
community: element
.findElements('media:community')
.map((e) => Community.parse(e))
.firstOrNull,
comments: element
.findElements('media:comments')
.firstOrNull
?.findElements('media:comment')
.map((e) {
return e.text;
}).toList() ??
.map((e) => e.text)
.toList() ??
[],
embed: Embed.parse(
findFirstElement(element, 'media:embed'),
),
responses: findFirstElement(element, 'media:responses')
embed: element
.findElements('media:embed')
.map((e) => Embed.parse(e))
.firstOrNull,
responses: element
.findElements('media:responses')
.firstOrNull
?.findElements('media:response')
.map((e) {
return e.text;
}).toList() ??
.map((e) => e.text)
.toList() ??
[],
backLinks: findFirstElement(element, 'media:backLinks')
backLinks: element
.findElements('media:backLinks')
.firstOrNull
?.findElements('media:backLink')
.map((e) {
return e.text;
}).toList() ??
.map((e) => e.text)
.toList() ??
[],
status: Status.parse(
findFirstElement(element, 'media:status'),
),
prices: element.findElements('media:price').map((e) {
return Price.parse(e);
}).toList(),
license: License.parse(
findFirstElement(element, 'media:license'),
),
peerLink: PeerLink.parse(
findFirstElement(element, 'media:peerLink'),
),
rights: Rights.parse(
findFirstElement(element, 'media:rights'),
),
scenes: findFirstElement(element, 'media:scenes')
status: element
.findElements('media:status')
.map((e) => Status.parse(e))
.firstOrNull,
prices: element
.findElements('media:price')
.map((e) => Price.parse(e))
.toList(),
license: element
.findElements('media:license')
.map((e) => License.parse(e))
.firstOrNull,
peerLink: element
.findElements('media:peerLink')
.map((e) => PeerLink.parse(e))
.firstOrNull,
rights: element
.findElements('media:rights')
.map((e) => Rights.parse(e))
.firstOrNull,
scenes: element
.findElements('media:scenes')
.firstOrNull
?.findElements('media:scene')
.map((e) {
return Scene.parse(e);
}).toList() ??
.map((e) => Scene.parse(e))
.toList() ??
[],
);
}


+ 1
- 2
lib/domain/media/param.dart Просмотреть файл

@@ -9,8 +9,7 @@ class Param {
this.value,
});

static Param? parse(XmlElement? element) {
if (element == null) return null;
factory Param.parse(XmlElement element) {
return Param(
name: element.getAttribute('name'),
value: element.text,


+ 1
- 2
lib/domain/media/peer_link.dart Просмотреть файл

@@ -11,8 +11,7 @@ class PeerLink {
this.value,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory PeerLink.parse(XmlElement element) {
return PeerLink(
type: element.getAttribute('type'),
href: element.getAttribute('href'),


+ 1
- 2
lib/domain/media/player.dart Просмотреть файл

@@ -13,8 +13,7 @@ class Player {
this.value,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory Player.parse(XmlElement element) {
return Player(
url: element.getAttribute('url'),
width: int.tryParse(element.getAttribute('width') ?? '0'),


+ 1
- 2
lib/domain/media/rating.dart Просмотреть файл

@@ -9,8 +9,7 @@ class Rating {
this.value,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory Rating.parse(XmlElement element) {
return Rating(
scheme: element.getAttribute('scheme'),
value: element.text,


+ 1
- 2
lib/domain/media/restriction.dart Просмотреть файл

@@ -11,8 +11,7 @@ class Restriction {
this.value,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory Restriction.parse(XmlElement element) {
return Restriction(
relationship: element.getAttribute('relationship'),
type: element.getAttribute('type'),


+ 1
- 2
lib/domain/media/rights.dart Просмотреть файл

@@ -7,8 +7,7 @@ class Rights {
this.status,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory Rights.parse(XmlElement element) {
return Rights(
status: element.getAttribute('status'),
);


+ 6
- 7
lib/domain/media/scene.dart Просмотреть файл

@@ -1,4 +1,4 @@
import 'package:webfeed/util/xml.dart';
import 'package:webfeed/util/iterable.dart';
import 'package:xml/xml.dart';

class Scene {
@@ -14,13 +14,12 @@ class Scene {
this.endTime,
});

static Scene? parse(XmlElement? element) {
if (element == null) return null;
factory Scene.parse(XmlElement element) {
return Scene(
title: findFirstElement(element, 'sceneTitle')?.text,
description: findFirstElement(element, 'sceneDescription')?.text,
startTime: findFirstElement(element, 'sceneStartTime')?.text,
endTime: findFirstElement(element, 'sceneEndTime')?.text,
title: element.findElements('sceneTitle').firstOrNull?.text,
description: element.findElements('sceneDescription').firstOrNull?.text,
startTime: element.findElements('sceneStartTime').firstOrNull?.text,
endTime: element.findElements('sceneEndTime').firstOrNull?.text,
);
}
}

+ 1
- 2
lib/domain/media/status.dart Просмотреть файл

@@ -9,8 +9,7 @@ class Status {
this.reason,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory Status.parse(XmlElement element) {
return Status(
state: element.getAttribute('state'),
reason: element.getAttribute('reason'),


+ 1
- 2
lib/domain/media/tags.dart Просмотреть файл

@@ -9,8 +9,7 @@ class Tags {
this.weight,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory Tags.parse(XmlElement element) {
return Tags(
tags: element.text,
weight: int.tryParse(element.getAttribute('weight') ?? '1'),


+ 1
- 2
lib/domain/media/text.dart Просмотреть файл

@@ -15,8 +15,7 @@ class Text {
this.value,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory Text.parse(XmlElement element) {
return Text(
type: element.getAttribute('type'),
lang: element.getAttribute('lang'),


+ 1
- 2
lib/domain/media/title.dart Просмотреть файл

@@ -9,8 +9,7 @@ class Title {
this.value,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory Title.parse(XmlElement element) {
return Title(
type: element.getAttribute('type'),
value: element.text,


+ 1
- 2
lib/domain/rss_category.dart Просмотреть файл

@@ -6,8 +6,7 @@ class RssCategory {

RssCategory(this.domain, this.value);

static RssCategory? parse(XmlElement? element) {
if (element == null) return null;
factory RssCategory.parse(XmlElement element) {
var domain = element.getAttribute('domain');
var value = element.text;



+ 1
- 2
lib/domain/rss_cloud.dart Просмотреть файл

@@ -15,8 +15,7 @@ class RssCloud {
this.protocol,
);

static parse(XmlElement? node) {
if (node == null) return null;
factory RssCloud.parse(XmlElement node) {
var domain = node.getAttribute('domain');
var port = node.getAttribute('port');
var path = node.getAttribute('path');


+ 4
- 7
lib/domain/rss_content.dart Просмотреть файл

@@ -12,18 +12,15 @@ final _imagesRegExp = RegExp(
///
class RssContent {
String value;
Iterable<String?> images;
Iterable<String> images;

RssContent(this.value, this.images);

static parse(XmlElement? element) {
if(element == null) {
return null;
}
factory RssContent.parse(XmlElement element) {
final dynamic? content = element.text;
final images = <String?>[];
final images = <String>[];
_imagesRegExp.allMatches(content).forEach((match) {
images.add(match.group(1));
images.add(match.group(1)!);
});
return RssContent(content, images);
}


+ 1
- 2
lib/domain/rss_enclosure.dart Просмотреть файл

@@ -7,8 +7,7 @@ class RssEnclosure {

RssEnclosure(this.url, this.type, this.length);

static parse(XmlElement? element) {
if (element == null) return null;
factory RssEnclosure.parse(XmlElement element) {
var url = element.getAttribute('url');
var type = element.getAttribute('type');
var length = int.tryParse(element.getAttribute('length') ?? '0');


+ 38
- 26
lib/domain/rss_feed.dart Просмотреть файл

@@ -7,7 +7,7 @@ import 'package:webfeed/domain/rss_cloud.dart';
import 'package:webfeed/domain/rss_image.dart';
import 'package:webfeed/domain/rss_item.dart';
import 'package:webfeed/domain/syndication/syndication.dart';
import 'package:webfeed/util/xml.dart';
import 'package:webfeed/util/iterable.dart';
import 'package:xml/xml.dart';

class RssFeed {
@@ -19,9 +19,9 @@ class RssFeed {

final RssImage? image;
final RssCloud? cloud;
final List<RssCategory?>? categories;
final List<RssCategory>? categories;
final List<String>? skipDays;
final List<int?>? skipHours;
final List<int>? skipHours;
final String? lastBuildDate;
final String? language;
final String? generator;
@@ -62,50 +62,62 @@ class RssFeed {

factory RssFeed.parse(String xmlString) {
var document = XmlDocument.parse(xmlString);
var rss = findFirstElement(document, 'rss');
var rdf = findFirstElement(document, 'rdf:RDF');
var rss = document.findElements('rss').firstOrNull;
var rdf = document.findElements('rdf:RDF').firstOrNull;
if (rss == null && rdf == null) {
throw ArgumentError('not a rss feed');
}
var channelElement = findFirstElement(rss ?? rdf, 'channel');
var channelElement = (rss ?? rdf)!.findElements('channel').firstOrNull;
if (channelElement == null) {
throw ArgumentError('channel not found');
}
return RssFeed(
title: findFirstElement(channelElement, 'title')?.text,
author: findFirstElement(channelElement, 'author')?.text,
description: findFirstElement(channelElement, 'description')?.text,
link: findFirstElement(channelElement, 'link')?.text,
items: (rss != null ? channelElement : rdf)!
title: channelElement.findElements('title').firstOrNull?.text,
author: channelElement.findElements('author').firstOrNull?.text,
description: channelElement.findElements('description').firstOrNull?.text,
link: channelElement.findElements('link').firstOrNull?.text,
items: (rdf ?? channelElement)
.findElements('item')
.map((e) => RssItem.parse(e))
.toList(),
image: RssImage.parse(
findFirstElement(rss != null ? channelElement : rdf, 'image')),
cloud: RssCloud.parse(findFirstElement(channelElement, 'cloud')),
image: (rdf ?? channelElement)
.findElements('image')
.map((e) => RssImage.parse(e))
.firstOrNull,
cloud: channelElement
.findElements('cloud')
.map((e) => RssCloud.parse(e))
.firstOrNull,
categories: channelElement
.findElements('category')
.map((e) => RssCategory.parse(e))
.toList(),
skipDays: findFirstElement(channelElement, 'skipDays')
skipDays: channelElement
.findElements('skipDays')
.firstOrNull
?.findAllElements('day')
.map((e) => e.text)
.toList() ??
[],
skipHours: findFirstElement(channelElement, 'skipHours')
skipHours: channelElement
.findElements('skipHours')
.firstOrNull
?.findAllElements('hour')
.map((e) => int.tryParse(e.text))
.map((e) => int.tryParse(e.text) ?? 0)
.toList() ??
[],
lastBuildDate: findFirstElement(channelElement, 'lastBuildDate')?.text,
language: findFirstElement(channelElement, 'language')?.text,
generator: findFirstElement(channelElement, 'generator')?.text,
copyright: findFirstElement(channelElement, 'copyright')?.text,
docs: findFirstElement(channelElement, 'docs')?.text,
managingEditor: findFirstElement(channelElement, 'managingEditor')?.text,
rating: findFirstElement(channelElement, 'rating')?.text,
webMaster: findFirstElement(channelElement, 'webMaster')?.text,
ttl: int.tryParse(findFirstElement(channelElement, 'ttl')?.text ?? '0'),
lastBuildDate:
channelElement.findElements('lastBuildDate').firstOrNull?.text,
language: channelElement.findElements('language').firstOrNull?.text,
generator: channelElement.findElements('generator').firstOrNull?.text,
copyright: channelElement.findElements('copyright').firstOrNull?.text,
docs: channelElement.findElements('docs').firstOrNull?.text,
managingEditor:
channelElement.findElements('managingEditor').firstOrNull?.text,
rating: channelElement.findElements('rating').firstOrNull?.text,
webMaster: channelElement.findElements('webMaster').firstOrNull?.text,
ttl: int.tryParse(
channelElement.findElements('ttl').firstOrNull?.text ?? '0'),
dc: DublinCore.parse(channelElement),
itunes: Itunes.parse(channelElement),
syndication: Syndication.parse(channelElement),


+ 5
- 6
lib/domain/rss_image.dart Просмотреть файл

@@ -1,4 +1,4 @@
import 'package:webfeed/util/xml.dart';
import 'package:webfeed/util/iterable.dart';
import 'package:xml/xml.dart';

class RssImage {
@@ -8,12 +8,11 @@ class RssImage {

RssImage({this.title, this.url, this.link});

static parse(XmlElement? element) {
if (element == null) return null;
factory RssImage.parse(XmlElement element) {
return RssImage(
title: findFirstElement(element, 'title')?.text,
url: findFirstElement(element, 'url')?.text,
link: findFirstElement(element, 'link')?.text,
title: element.findElements('title').firstOrNull?.text,
url: element.findElements('url').firstOrNull?.text,
link: element.findElements('link').firstOrNull?.text,
);
}
}

+ 21
- 12
lib/domain/rss_item.dart Просмотреть файл

@@ -6,7 +6,7 @@ import 'package:webfeed/domain/rss_content.dart';
import 'package:webfeed/domain/rss_enclosure.dart';
import 'package:webfeed/domain/rss_source.dart';
import 'package:webfeed/util/datetime.dart';
import 'package:webfeed/util/xml.dart';
import 'package:webfeed/util/iterable.dart';
import 'package:xml/xml.dart';

class RssItem {
@@ -14,7 +14,7 @@ class RssItem {
final String? description;
final String? link;

final List<RssCategory?>? categories;
final List<RssCategory>? categories;
final String? guid;
final DateTime? pubDate;
final String? author;
@@ -45,21 +45,30 @@ class RssItem {

factory RssItem.parse(XmlElement element) {
return RssItem(
title: findFirstElement(element, 'title')?.text,
description: findFirstElement(element, 'description')?.text,
link: findFirstElement(element, 'link')?.text,
title: element.findElements('title').firstOrNull?.text,
description: element.findElements('description').firstOrNull?.text,
link: element.findElements('link').firstOrNull?.text,
categories: element
.findElements('category')
.map((e) => RssCategory.parse(e))
.toList(),
guid: findFirstElement(element, 'guid')?.text,
pubDate: parseDateTime(findFirstElement(element, 'pubDate')?.text),
author: findFirstElement(element, 'author')?.text,
comments: findFirstElement(element, 'comments')?.text,
source: RssSource.parse(findFirstElement(element, 'source')),
content: RssContent.parse(findFirstElement(element, 'content:encoded')),
guid: element.findElements('guid').firstOrNull?.text,
pubDate: parseDateTime(element.findElements('pubDate').firstOrNull?.text),
author: element.findElements('author').firstOrNull?.text,
comments: element.findElements('comments').firstOrNull?.text,
source: element
.findElements('source')
.map((e) => RssSource.parse(e))
.firstOrNull,
content: element
.findElements('content:encoded')
.map((e) => RssContent.parse(e))
.firstOrNull,
media: Media.parse(element),
enclosure: RssEnclosure.parse(findFirstElement(element, 'enclosure')),
enclosure: element
.findElements('enclosure')
.map((e) => RssEnclosure.parse(e))
.firstOrNull,
dc: DublinCore.parse(element),
itunes: Itunes.parse(element),
);


+ 1
- 2
lib/domain/rss_source.dart Просмотреть файл

@@ -6,8 +6,7 @@ class RssSource {

RssSource(this.url, this.value);

static parse(XmlElement? element) {
if (element == null) return null;
factory RssSource.parse(XmlElement element) {
var url = element.getAttribute('url');
var value = element.text;



+ 6
- 7
lib/domain/syndication/syndication.dart Просмотреть файл

@@ -1,5 +1,5 @@
import 'package:webfeed/util/datetime.dart';
import 'package:webfeed/util/xml.dart';
import 'package:webfeed/util/iterable.dart';
import 'package:xml/xml.dart';

enum SyndicationUpdatePeriod { hourly, daily, weekly, monthly, yearly }
@@ -15,10 +15,9 @@ class Syndication {
this.updateBase,
});

static parse(XmlElement? element) {
if (element == null) return null;
factory Syndication.parse(XmlElement element) {
SyndicationUpdatePeriod updatePeriod;
switch (findFirstElement(element, 'sy:updatePeriod')?.text) {
switch (element.findElements('sy:updatePeriod').firstOrNull?.text) {
case 'hourly':
updatePeriod = SyndicationUpdatePeriod.hourly;
break;
@@ -41,9 +40,9 @@ class Syndication {
return Syndication(
updatePeriod: updatePeriod,
updateFrequency: int.tryParse(
findFirstElement(element, 'sy:updateFrequency')?.text ?? '1'),
updateBase:
parseDateTime(findFirstElement(element, 'sy:updateBase')?.text),
element.findElements('sy:updateFrequency').firstOrNull?.text ?? '1'),
updateBase: parseDateTime(
element.findElements('sy:updateBase').firstOrNull?.text),
);
}
}

+ 0
- 0
lib/util/function.dart Просмотреть файл


+ 3
- 0
lib/util/iterable.dart Просмотреть файл

@@ -0,0 +1,3 @@
extension WebFeedIterable<T> on Iterable<T> {
T? get firstOrNull => isEmpty ? null : first;
}

+ 2
- 15
lib/util/xml.dart Просмотреть файл

@@ -1,21 +1,8 @@
import 'dart:core';

import 'package:webfeed/util/iterable.dart';
import 'package:xml/xml.dart';

XmlElement? findFirstElement(
XmlNode? node,
String name, {
bool recursive = false,
String? namespace,
}) {
try {
return findElements(node, name, recursive: recursive, namespace: namespace)
?.first;
} on StateError {
return null;
}
}

Iterable<XmlElement>? findElements(
XmlNode? node,
String name, {
@@ -34,7 +21,7 @@ Iterable<XmlElement>? findElements(
}

bool parseBoolLiteral(XmlElement element, String tagName) {
var v = findFirstElement(element, tagName)?.text.toLowerCase().trim();
var v = element.findElements(tagName).firstOrNull?.text.toLowerCase().trim();
if (v == null) return false;
return ['yes', 'true'].contains(v);
}

+ 9
- 9
test/atom_test.dart Просмотреть файл

@@ -185,9 +185,9 @@ void main() {
expect(item.media!.embed!.width, 512);
expect(item.media!.embed!.height, 323);
expect(item.media!.embed!.params!.length, 5);
expect(item.media!.embed!.params!.first!.name, 'type');
expect(
item.media!.embed!.params!.first!.value, 'application/x-shockwave-flash');
expect(item.media!.embed!.params!.first.name, 'type');
expect(item.media!.embed!.params!.first.value,
'application/x-shockwave-flash');

expect(item.media!.responses!.length, 2);
expect(item.media!.responses!.first, 'http://www.response1.com');
@@ -203,8 +203,8 @@ void main() {
expect(item.media!.prices!.length, 2);
expect(item.media!.prices!.first.price, 19.99);
expect(item.media!.prices!.first.type, 'rent');
expect(
item.media!.prices!.first.info, 'http://www.dummy.jp/package_info.html');
expect(item.media!.prices!.first.info,
'http://www.dummy.jp/package_info.html');
expect(item.media!.prices!.first.currency, 'EUR');

expect(item.media!.license!.type, 'text/html');
@@ -218,10 +218,10 @@ void main() {
expect(item.media!.rights!.status, 'official');

expect(item.media!.scenes!.length, 2);
expect(item.media!.scenes!.first!.title, 'sceneTitle1');
expect(item.media!.scenes!.first!.description, 'sceneDesc1');
expect(item.media!.scenes!.first!.startTime, '00:15');
expect(item.media!.scenes!.first!.endTime, '00:45');
expect(item.media!.scenes!.first.title, 'sceneTitle1');
expect(item.media!.scenes!.first.description, 'sceneDesc1');
expect(item.media!.scenes!.first.startTime, '00:15');
expect(item.media!.scenes!.first.endTime, '00:45');
});

test('parse Atom-Empty.xml', () {


+ 18
- 18
test/rss_test.dart Просмотреть файл

@@ -47,10 +47,10 @@ void main() {
expect(feed.cloud!.protocol, 'xml-rpc');

expect(feed.categories!.length, 2);
expect(feed.categories![0]!.domain, null);
expect(feed.categories![0]!.value, 'Ipsum');
expect(feed.categories![1]!.domain, 'news');
expect(feed.categories![1]!.value, 'Lorem Ipsum');
expect(feed.categories![0].domain, null);
expect(feed.categories![0].value, 'Ipsum');
expect(feed.categories![1].domain, 'news');
expect(feed.categories![1].value, 'Lorem Ipsum');

expect(feed.skipDays!.length, 3);
expect(feed.skipDays!.contains('Monday'), true);
@@ -74,8 +74,8 @@ void main() {
expect(feed.items!.first.guid, 'https://foo.bar.news/1?guid');
expect(feed.items!.first.pubDate,
DateTime(2018, 03, 26, 14)); //Mon, 26 Mar 2018 14:00:00 PDT
expect(feed.items!.first.categories!.first!.domain, 'news');
expect(feed.items!.first.categories!.first!.value, 'Lorem');
expect(feed.items!.first.categories!.first.domain, 'news');
expect(feed.items!.first.categories!.first.value, 'Lorem');
expect(feed.items!.first.author, 'alice@foo.bar.news');
expect(feed.items!.first.source!.url, 'https://foo.bar.news/1?source');
expect(feed.items!.first.source!.value, 'Foo Bar');
@@ -192,9 +192,9 @@ void main() {
expect(item.media!.embed!.width, 512);
expect(item.media!.embed!.height, 323);
expect(item.media!.embed!.params!.length, 5);
expect(item.media!.embed!.params!.first!.name, 'type');
expect(
item.media!.embed!.params!.first!.value, 'application/x-shockwave-flash');
expect(item.media!.embed!.params!.first.name, 'type');
expect(item.media!.embed!.params!.first.value,
'application/x-shockwave-flash');

expect(item.media!.responses!.length, 2);
expect(item.media!.responses!.first, 'http://www.response1.com');
@@ -210,8 +210,8 @@ void main() {
expect(item.media!.prices!.length, 2);
expect(item.media!.prices!.first.price, 19.99);
expect(item.media!.prices!.first.type, 'rent');
expect(
item.media!.prices!.first.info, 'http://www.dummy.jp/package_info.html');
expect(item.media!.prices!.first.info,
'http://www.dummy.jp/package_info.html');
expect(item.media!.prices!.first.currency, 'EUR');

expect(item.media!.license!.type, 'text/html');
@@ -225,10 +225,10 @@ void main() {
expect(item.media!.rights!.status, 'official');

expect(item.media!.scenes!.length, 2);
expect(item.media!.scenes!.first!.title, 'sceneTitle1');
expect(item.media!.scenes!.first!.description, 'sceneDesc1');
expect(item.media!.scenes!.first!.startTime, '00:15');
expect(item.media!.scenes!.first!.endTime, '00:45');
expect(item.media!.scenes!.first.title, 'sceneTitle1');
expect(item.media!.scenes!.first.description, 'sceneDesc1');
expect(item.media!.scenes!.first.startTime, '00:15');
expect(item.media!.scenes!.first.endTime, '00:45');
});
test('parse RSS-DC.xml', () {
var xmlString = File('test/xml/RSS-DC.xml').readAsStringSync();
@@ -332,12 +332,12 @@ void main() {
expect(feed.itunes!.owner!.email, 'editors@changelog.com');
expect(
Set.from([
feed.itunes!.categories![0]!.category,
feed.itunes!.categories![1]!.category
feed.itunes!.categories![0].category,
feed.itunes!.categories![1].category
]),
['Technology', 'Foo']);
for (var category in feed.itunes!.categories!) {
switch (category!.category) {
switch (category.category) {
case 'Foo':
expect(category.subCategories, ['Bar', 'Baz']);
break;


Загрузка…
Отмена
Сохранить