Refactoring to v.2.0

This commit is contained in:
relikd
2018-12-27 21:11:59 +01:00
parent f9e672661a
commit 62c5bef463
50 changed files with 2574 additions and 3128 deletions

View File

@@ -1,10 +1,25 @@
//
// RSDateParserTests.m
// RSXML
// MIT License (MIT)
//
// Created by Brent Simmons on 12/26/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
// Copyright (c) 2016 Brent Simmons
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import <XCTest/XCTest.h>
@import RSXML;

View File

@@ -1,10 +1,25 @@
//
// RSEntityTests.m
// RSXML
// MIT License (MIT)
//
// Created by Brent Simmons on 12/26/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
// Copyright (c) 2016 Brent Simmons
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import <XCTest/XCTest.h>
@import RSXML;
@@ -15,7 +30,6 @@
@implementation RSEntityTests
- (void)testInnerAmpersand {
NSString *expectedResult = @"A&P";

View File

@@ -1,13 +1,29 @@
//
// RSHTMLTests.m
// RSXML
// MIT License (MIT)
//
// Created by Brent Simmons on 3/5/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
// Copyright (c) 2016 Brent Simmons
// Copyright (c) 2018 Oleg Geier
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
@import RSXML;
#import <XCTest/XCTest.h>
@import RSXML;
@interface RSHTMLTests : XCTestCase
@@ -15,169 +31,109 @@
@implementation RSHTMLTests
+ (NSArray<XCTPerformanceMetric> *)defaultPerformanceMetrics {
return @[XCTPerformanceMetric_WallClockTime, @"com.apple.XCTPerformanceMetric_TotalHeapAllocationsKilobytes"];
}
+ (RSXMLData *)xmlData:(NSString *)title urlString:(NSString *)urlString {
- (RSXMLData *)xmlData:(NSString *)title urlString:(NSString *)urlString {
NSString *s = [[NSBundle bundleForClass:[self class]] pathForResource:title ofType:@"html" inDirectory:@"Resources"];
NSData *d = [[NSData alloc] initWithContentsOfFile:s];
return [[RSXMLData alloc] initWithData:d urlString:urlString];
return [[RSXMLData alloc] initWithData:[[NSData alloc] initWithContentsOfFile:s] urlString:urlString];
}
+ (RSXMLData *)daringFireballData {
static RSXMLData *xmlData = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
xmlData = [self xmlData:@"DaringFireball" urlString:@"http://daringfireball.net/"];
});
return xmlData;
}
+ (RSXMLData *)furboData {
static RSXMLData *xmlData = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
xmlData = [self xmlData:@"furbo" urlString:@"http://furbo.org/"];
});
return xmlData;
}
+ (RSXMLData *)inessentialData {
static RSXMLData *xmlData = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
xmlData = [self xmlData:@"inessential" urlString:@"http://inessential.com/"];
});
return xmlData;
}
+ (RSXMLData *)sixcolorsData {
static RSXMLData *xmlData = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
xmlData = [self xmlData:@"sixcolors" urlString:@"https://sixcolors.com/"];
});
return xmlData;
}
- (void)testDaringFireball {
RSXMLData *xmlData = [[self class] daringFireballData];
RSHTMLMetadata *metadata = [RSHTMLMetadataParser HTMLMetadataWithXMLData:xmlData];
RSXMLData *xmlData = [self xmlData:@"DaringFireball" urlString:@"http://daringfireball.net/"];
XCTAssertTrue([xmlData.parserClass isHTMLParser]);
RSHTMLMetadataParser *parser = [[RSHTMLMetadataParser alloc] initWithXMLData:xmlData];
NSError *error;
RSHTMLMetadata *metadata = [parser parseSync:&error];
XCTAssertNil(error);
XCTAssertEqualObjects(metadata.faviconLink, @"http://daringfireball.net/graphics/favicon.ico?v=005");
XCTAssertTrue(metadata.feedLinks.count == 1);
RSHTMLMetadataFeedLink *feedLink = metadata.feedLinks[0];
XCTAssertNil(feedLink.title);
XCTAssertEqualObjects(feedLink.type, @"application/atom+xml");
XCTAssertEqualObjects(feedLink.urlString, @"http://daringfireball.net/feeds/main");
}
- (void)testDaringFireballPerformance {
RSXMLData *xmlData = [[self class] daringFireballData];
XCTAssertEqual(feedLink.type, RSFeedTypeAtom);
XCTAssertEqualObjects(feedLink.link, @"http://daringfireball.net/feeds/main");
[self measureBlock:^{
(void)[RSHTMLMetadataParser HTMLMetadataWithXMLData:xmlData];
for (int i = 0; i < 10; i++)
[parser parseSync:nil];
}];
}
- (void)testFurbo {
RSXMLData *xmlData = [[self class] furboData];
RSHTMLMetadata *metadata = [RSHTMLMetadataParser HTMLMetadataWithXMLData:xmlData];
RSXMLData *xmlData = [self xmlData:@"furbo" urlString:@"http://furbo.org/"];
XCTAssertTrue([xmlData.parserClass isHTMLParser]);
RSHTMLMetadataParser *parser = [[RSHTMLMetadataParser alloc] initWithXMLData:xmlData];
NSError *error;
RSHTMLMetadata *metadata = [parser parseSync:&error];
XCTAssertNil(error);
XCTAssertEqualObjects(metadata.faviconLink, @"http://furbo.org/favicon.ico");
XCTAssertTrue(metadata.feedLinks.count == 1);
RSHTMLMetadataFeedLink *feedLink = metadata.feedLinks[0];
XCTAssertEqualObjects(feedLink.title, @"Iconfactory News Feed");
XCTAssertEqualObjects(feedLink.type, @"application/rss+xml");
}
- (void)testFurboPerformance {
RSXMLData *xmlData = [[self class] furboData];
XCTAssertEqual(feedLink.type, RSFeedTypeRSS);
[self measureBlock:^{
(void)[RSHTMLMetadataParser HTMLMetadataWithXMLData:xmlData];
for (int i = 0; i < 10; i++)
[parser parseSync:nil];
}];
}
- (void)testInessential {
RSXMLData *xmlData = [[self class] inessentialData];
RSHTMLMetadata *metadata = [RSHTMLMetadataParser HTMLMetadataWithXMLData:xmlData];
RSXMLData *xmlData = [self xmlData:@"inessential" urlString:@"http://inessential.com/"];
XCTAssertTrue([xmlData.parserClass isHTMLParser]);
RSHTMLMetadataParser *parser = [[RSHTMLMetadataParser alloc] initWithXMLData:xmlData];
NSError *error;
RSHTMLMetadata *metadata = [parser parseSync:&error];
XCTAssertNil(error);
XCTAssertNil(metadata.faviconLink);
XCTAssertTrue(metadata.feedLinks.count == 1);
RSHTMLMetadataFeedLink *feedLink = metadata.feedLinks[0];
XCTAssertEqualObjects(feedLink.title, @"RSS");
XCTAssertEqualObjects(feedLink.type, @"application/rss+xml");
XCTAssertEqualObjects(feedLink.urlString, @"http://inessential.com/xml/rss.xml");
XCTAssertEqual(metadata.appleTouchIcons.count, 0u);
}
- (void)testInessentialPerformance {
RSXMLData *xmlData = [[self class] inessentialData];
XCTAssertEqual(feedLink.type, RSFeedTypeRSS);
XCTAssertEqualObjects(feedLink.link, @"http://inessential.com/xml/rss.xml");
XCTAssertEqual(metadata.iconLinks.count, 0u);
[self measureBlock:^{
(void)[RSHTMLMetadataParser HTMLMetadataWithXMLData:xmlData];
for (int i = 0; i < 10; i++)
[parser parseSync:nil];
}];
}
- (void)testSixcolors {
RSXMLData *xmlData = [[self class] sixcolorsData];
RSHTMLMetadata *metadata = [RSHTMLMetadataParser HTMLMetadataWithXMLData:xmlData];
RSXMLData *xmlData = [self xmlData:@"sixcolors" urlString:@"https://sixcolors.com/"];
XCTAssertTrue([xmlData.parserClass isHTMLParser]);
RSHTMLMetadataParser *parser = [[RSHTMLMetadataParser alloc] initWithXMLData:xmlData];
NSError *error;
RSHTMLMetadata *metadata = [parser parseSync:&error];
XCTAssertNil(error);
XCTAssertEqualObjects(metadata.faviconLink, @"https://sixcolors.com/images/favicon.ico");
XCTAssertTrue(metadata.feedLinks.count == 1);
RSHTMLMetadataFeedLink *feedLink = metadata.feedLinks[0];
XCTAssertEqualObjects(feedLink.title, @"RSS");
XCTAssertEqualObjects(feedLink.type, @"application/rss+xml");
XCTAssertEqualObjects(feedLink.urlString, @"http://feedpress.me/sixcolors");
XCTAssertEqual(feedLink.type, RSFeedTypeRSS);
XCTAssertEqualObjects(feedLink.link, @"http://feedpress.me/sixcolors");
XCTAssertEqual(metadata.appleTouchIcons.count, 6u);
RSHTMLMetadataAppleTouchIcon *icon = metadata.appleTouchIcons[3];
XCTAssertEqualObjects(icon.rel, @"apple-touch-icon");
XCTAssertEqual(metadata.iconLinks.count, 6u);
RSHTMLMetadataIconLink *icon = metadata.iconLinks[3];
XCTAssertEqualObjects(icon.title, @"apple-touch-icon");
XCTAssertEqualObjects(icon.sizes, @"120x120");
XCTAssertEqualObjects(icon.urlString, @"https://sixcolors.com/apple-touch-icon-120.png");
}
- (void)testSixcolorsPerformance {
RSXMLData *xmlData = [[self class] sixcolorsData];
XCTAssertEqual([icon getSize].width, 120);
XCTAssertEqualObjects(icon.link, @"https://sixcolors.com/apple-touch-icon-120.png");
[self measureBlock:^{
(void)[RSHTMLMetadataParser HTMLMetadataWithXMLData:xmlData];
for (int i = 0; i < 10; i++)
[parser parseSync:nil];
}];
}
@@ -185,32 +141,35 @@
- (void)testSixColorsLinks {
RSXMLData *xmlData = [[self class] sixcolorsData];
NSArray *links = [RSHTMLLinkParser htmlLinksWithData:xmlData];
NSString *linkToFind = @"https://www.theincomparable.com/theincomparable/290/index.php";
NSString *textToFind = @"this weeks episode of The Incomparable";
RSXMLData *xmlData = [self xmlData:@"sixcolors" urlString:@"https://sixcolors.com/"];
XCTAssertTrue([xmlData.parserClass isHTMLParser]);
RSHTMLLinkParser *parser = [[RSHTMLLinkParser alloc] initWithXMLData:xmlData];
NSError *error;
NSArray<RSHTMLMetadataAnchor*> *links = [parser parseSync:&error];
XCTAssertNil(error);
BOOL found = NO;
for (RSHTMLLink *oneLink in links) {
if ([oneLink.urlString isEqualToString:linkToFind] && [oneLink.text isEqualToString:textToFind]) {
for (RSHTMLMetadataAnchor *oneLink in links) {
if ([oneLink.title isEqualToString:@"this weeks episode of The Incomparable"] &&
[oneLink.link isEqualToString:@"https://www.theincomparable.com/theincomparable/290/index.php"])
{
found = YES;
break;
}
}
// item No 11 to ensure .text removes <em></em>
XCTAssertEqualObjects(links[11].title, @"Podcasting");
XCTAssertEqualObjects(links[11].link, @"https://sixcolors.com/topic/podcasting/");
// item No. 18 & 19 to ensure '<a>Topics</a>' is skipped
XCTAssertEqualObjects(links[18].title, @"Podcasts");
XCTAssertEqualObjects(links[18].link, @"https://sixcolors.com/podcasts/");
XCTAssertEqualObjects(links[19].title, @"Gift Guide");
XCTAssertEqualObjects(links[19].link, @"https://sixcolors.com/topic/giftguide/");
XCTAssertTrue(found, @"Expected link should have been found.");
XCTAssertEqual(links.count, 131u, @"Expected 131 links.");
}
- (void)testSixColorsLinksPerformance {
RSXMLData *xmlData = [[self class] sixcolorsData];
XCTAssertEqual(links.count, 130u, @"Expected 130 links.");
[self measureBlock:^{
(void)[RSHTMLLinkParser htmlLinksWithData:xmlData];
[parser parseSync:nil];
}];
}

View File

@@ -1,10 +1,26 @@
//
// RSOPMLTests.m
// RSXML
// MIT License (MIT)
//
// Created by Brent Simmons on 2/28/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
// Copyright (c) 2016 Brent Simmons
// Copyright (c) 2018 Oleg Geier
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import <XCTest/XCTest.h>
@import RSXML;
@@ -15,63 +31,62 @@
@implementation RSOPMLTests
+ (RSXMLData *)subsData {
+ (NSArray<XCTPerformanceMetric> *)defaultPerformanceMetrics {
return @[XCTPerformanceMetric_WallClockTime, @"com.apple.XCTPerformanceMetric_TotalHeapAllocationsKilobytes"];
}
static RSXMLData *xmlData = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *s = [[NSBundle bundleForClass:[self class]] pathForResource:@"Subs" ofType:@"opml" inDirectory:@"Resources"];
NSData *d = [[NSData alloc] initWithContentsOfFile:s];
xmlData = [[RSXMLData alloc] initWithData:d urlString:@"http://example.org/"];
});
return xmlData;
- (RSXMLData*)xmlFile:(NSString*)name extension:(NSString*)ext {
NSString *s = [[NSBundle bundleForClass:[self class]] pathForResource:name ofType:ext inDirectory:@"Resources"];
if (s == nil) return nil;
NSData *d = [[NSData alloc] initWithContentsOfFile:s];
return [[RSXMLData alloc] initWithData:d urlString:[NSString stringWithFormat:@"%@.%@", name, ext]];
}
- (void)testNotOPML {
NSString *s = [[NSBundle bundleForClass:[self class]] pathForResource:@"DaringFireball" ofType:@"rss" inDirectory:@"Resources"];
NSData *d = [[NSData alloc] initWithContentsOfFile:s];
RSXMLData *xmlData = [[RSXMLData alloc] initWithData:d urlString:@"http://example.org/"];
NSError *error;
RSXMLData *xmlData = [self xmlFile:@"DaringFireball" extension:@"atom"];
XCTAssertNotEqualObjects(xmlData.parserClass, [RSOPMLParser class]);
XCTAssertNil(xmlData.parserError);
RSOPMLParser *parser = [[RSOPMLParser alloc] initWithXMLData:xmlData];
XCTAssertNotNil(parser.error);
XCTAssert(parser.error.code == RSXMLErrorFileNotOPML);
XCTAssert([parser.error.domain isEqualTo:kRSXMLParserErrorDomain]);
RSOPMLItem *document = [parser parseSync:&error];
XCTAssertNil(document);
XCTAssertNotNil(error);
XCTAssertEqual(error.code, RSXMLErrorExpectingOPML);
XCTAssertEqualObjects(error.domain, kRSXMLParserErrorDomain);
d = [[NSData alloc] initWithContentsOfFile:@"/System/Library/Kernels/kernel"];
xmlData = [[RSXMLData alloc] initWithData:d urlString:@"/System/Library/Kernels/kernel"];
parser = [[RSOPMLParser alloc] initWithXMLData:xmlData];
XCTAssertNotNil(parser.error);
xmlData = [[RSXMLData alloc] initWithData:[[NSData alloc] initWithContentsOfFile:@"/System/Library/Kernels/kernel"]
urlString:@"/System/Library/Kernels/kernel"];
XCTAssertNotNil(xmlData.parserError);
XCTAssert(xmlData.parserError.code == RSXMLErrorMissingLeftCaret);
RSXMLParser *parser2 = [xmlData getParser];
XCTAssertNil(parser2);
XCTAssertNotNil(xmlData.parserError);
XCTAssert(xmlData.parserError.code == RSXMLErrorMissingLeftCaret); // error should not be overwritten
}
- (void)testSubsPerformance {
RSXMLData *xmlData = [[self class] subsData];
[self measureBlock:^{
(void)[[RSOPMLParser alloc] initWithXMLData:xmlData];
}];
}
- (void)testSubsStructure {
RSXMLData *xmlData = [[self class] subsData];
RSOPMLParser *parser = [[RSOPMLParser alloc] initWithXMLData:xmlData];
XCTAssertNotNil(parser);
RSOPMLItem *document = parser.opmlDocument;
RSXMLData<RSOPMLParser*> *xmlData = [self xmlFile:@"Subs" extension:@"opml"];
XCTAssertEqualObjects(xmlData.parserClass, [RSOPMLParser class]);
NSError *error;
RSOPMLParser *parser = [xmlData getParser];
RSOPMLItem *document = [parser parseSync:&error];
XCTAssertNotNil(document);
XCTAssert([document.displayName isEqualToString:@"Subs"]);
XCTAssert([document.children.firstObject.displayName isEqualToString:@"Daring Fireball"]);
XCTAssert([document.children.lastObject.displayName isEqualToString:@"Writers"]);
XCTAssert([document.children.lastObject.children.lastObject.displayName isEqualToString:@"Gerrold"]);
XCTAssertEqualObjects(document.displayName, @"Subs");
XCTAssertEqualObjects(document.children.firstObject.displayName, @"Daring Fireball");
XCTAssertEqualObjects(document.children.lastObject.displayName, @"Writers");
XCTAssertEqualObjects(document.children.lastObject.children.lastObject.displayName, @"Gerrold");
[self checkStructureForOPMLItem:document isRoot:YES];
//NSLog(@"\n%@", [document recursiveDescription]);
[self measureBlock:^{
[parser parseSync:nil];
}];
}
- (void)checkStructureForOPMLItem:(RSOPMLItem *)item isRoot:(BOOL)root {
@@ -98,5 +113,4 @@
}
}
@end

View File

@@ -1,10 +1,26 @@
//
// RSXMLTests.m
// RSXMLTests
// MIT License (MIT)
//
// Created by Brent Simmons on 7/12/15.
// Copyright © 2015 Ranchero Software, LLC. All rights reserved.
// Copyright (c) 2016 Brent Simmons
// Copyright (c) 2018 Oleg Geier
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import <XCTest/XCTest.h>
@import RSXML;
@@ -15,226 +31,253 @@
@implementation RSXMLTests
+ (RSXMLData *)oftData {
static RSXMLData *xmlData = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *s = [[NSBundle bundleForClass:[self class]] pathForResource:@"OneFootTsunami" ofType:@"atom" inDirectory:@"Resources"];
NSData *d = [[NSData alloc] initWithContentsOfFile:s];
xmlData = [[RSXMLData alloc] initWithData:d urlString:@"http://onefoottsunami.com/"];
});
return xmlData;
/** @see https://indiestack.com/2018/02/xcodes-secret-performance-tests/
"com.apple.XCTPerformanceMetric_WallClockTime"
"com.apple.XCTPerformanceMetric_UserTime"
"com.apple.XCTPerformanceMetric_RunTime"
"com.apple.XCTPerformanceMetric_SystemTime"
"com.apple.XCTPerformanceMetric_HighWaterMarkForHeapAllocations"
"com.apple.XCTPerformanceMetric_HighWaterMarkForVMAllocations"
"com.apple.XCTPerformanceMetric_PersistentHeapAllocations"
"com.apple.XCTPerformanceMetric_PersistentHeapAllocationsNodes"
"com.apple.XCTPerformanceMetric_PersistentVMAllocations"
"com.apple.XCTPerformanceMetric_TemporaryHeapAllocationsKilobytes"
"com.apple.XCTPerformanceMetric_TotalHeapAllocationsKilobytes"
"com.apple.XCTPerformanceMetric_TransientHeapAllocationsKilobytes"
"com.apple.XCTPerformanceMetric_TransientHeapAllocationsNodes"
"com.apple.XCTPerformanceMetric_TransientVMAllocationsKilobytes"
*/
+ (NSArray<XCTPerformanceMetric> *)defaultPerformanceMetrics {
return @[XCTPerformanceMetric_WallClockTime, @"com.apple.XCTPerformanceMetric_TotalHeapAllocationsKilobytes"];
}
// http://onefoottsunami.com/
// http://scripting.com/
// http://manton.org/
// http://daringfireball.net/
// http://katiefloyd.com/
// https://medium.com/@emarley
+ (RSXMLData *)scriptingNewsData {
static RSXMLData *xmlData = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *s = [[NSBundle bundleForClass:[self class]] pathForResource:@"scriptingNews" ofType:@"rss" inDirectory:@"Resources"];
NSData *d = [[NSData alloc] initWithContentsOfFile:s];
xmlData = [[RSXMLData alloc] initWithData:d urlString:@"http://scripting.com/"];
});
return xmlData;
- (RSXMLData*)xmlFile:(NSString*)name extension:(NSString*)ext {
NSString *s = [[NSBundle bundleForClass:[self class]] pathForResource:name ofType:ext inDirectory:@"Resources"];
if (s == nil) return nil;
NSData *d = [[NSData alloc] initWithContentsOfFile:s];
return [[RSXMLData alloc] initWithData:d urlString:[NSString stringWithFormat:@"%@.%@", name, ext]];
}
+ (RSXMLData *)mantonData {
static RSXMLData *xmlData = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *s = [[NSBundle bundleForClass:[self class]] pathForResource:@"manton" ofType:@"rss" inDirectory:@"Resources"];
NSData *d = [[NSData alloc] initWithContentsOfFile:s];
xmlData = [[RSXMLData alloc] initWithData:d urlString:@"http://manton.org/"];
});
return xmlData;
- (RSFeedParser*)parserForFile:(NSString*)name extension:(NSString*)ext expect:(Class)cls {
RSXMLData<RSFeedParser*> *xmlData = [self xmlFile:name extension:ext];
XCTAssertEqual(xmlData.parserClass, cls);
return [xmlData getParser];
}
#pragma mark - Completeness Tests
+ (RSXMLData *)daringFireballData {
static RSXMLData *xmlData = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *s = [[NSBundle bundleForClass:[self class]] pathForResource:@"DaringFireball" ofType:@"rss" inDirectory:@"Resources"];
NSData *d = [[NSData alloc] initWithContentsOfFile:s];
xmlData = [[RSXMLData alloc] initWithData:d urlString:@"http://daringfireball.net/"];
});
return xmlData;
- (void)testAsync {
RSXMLData *xmlData = [self xmlFile:@"OneFootTsunami" extension:@"atom"];
[[xmlData getParser] parseAsync:^(RSParsedFeed *parsedDocument, NSError *error) {
XCTAssertEqualObjects(parsedDocument.title, @"One Foot Tsunami");
XCTAssertEqualObjects(parsedDocument.subtitle, @"Slightly less disappointing than it sounds");
XCTAssertEqualObjects(parsedDocument.link, @"http://onefoottsunami.com");
XCTAssertEqual(parsedDocument.articles.count, 25u);
RSParsedArticle *a = parsedDocument.articles.firstObject;
XCTAssertEqualObjects(a.title, @"Link: Pillow Fight Leaves 24 Concussed");
XCTAssertEqualObjects(a.link, @"http://www.nytimes.com/2015/09/05/us/at-west-point-annual-pillow-fight-becomes-weaponized.html?mwrsm=Email&_r=1&pagewanted=all");
XCTAssertEqualObjects(a.guid, @"http://onefoottsunami.com/?p=14863");
XCTAssertEqual(a.datePublished, [NSDate dateWithTimeIntervalSince1970:1441722101]); // 2015-09-08T14:21:41Z
}];
}
+ (RSXMLData *)katieFloydData {
static RSXMLData *xmlData = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *s = [[NSBundle bundleForClass:[self class]] pathForResource:@"KatieFloyd" ofType:@"rss" inDirectory:@"Resources"];
NSData *d = [[NSData alloc] initWithContentsOfFile:s];
xmlData = [[RSXMLData alloc] initWithData:d urlString:@"http://katiefloyd.com/"];
});
return xmlData;
}
+ (RSXMLData *)eMarleyData {
static RSXMLData *xmlData = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *s = [[NSBundle bundleForClass:[self class]] pathForResource:@"EMarley" ofType:@"rss" inDirectory:@"Resources"];
NSData *d = [[NSData alloc] initWithContentsOfFile:s];
xmlData = [[RSXMLData alloc] initWithData:d urlString:@"https://medium.com/@emarley"];
});
return xmlData;
}
- (void)testOneFootTsunami {
RSXMLData *xmlData = [self xmlFile:@"OneFootTsunami" extension:@"atom"];
XCTAssertEqual(xmlData.parserClass, [RSAtomParser class]);
NSError *error = nil;
RSXMLData *xmlData = [[self class] oftData];
RSParsedFeed *parsedFeed = RSParseFeedSync(xmlData, &error);
NSLog(@"parsedFeed: %@", parsedFeed);
}
- (void)testOFTPerformance {
RSXMLData *xmlData = [[self class] oftData];
RSParsedFeed *parsedFeed = [[xmlData getParser] parseSync:&error];
XCTAssertEqualObjects(parsedFeed.title, @"One Foot Tsunami");
XCTAssertEqualObjects(parsedFeed.subtitle, @"Slightly less disappointing than it sounds");
XCTAssertEqualObjects(parsedFeed.link, @"http://onefoottsunami.com");
XCTAssertEqual(parsedFeed.articles.count, 25u);
RSParsedArticle *a = parsedFeed.articles.firstObject;
XCTAssertEqualObjects(a.title, @"Link: Pillow Fight Leaves 24 Concussed");
XCTAssertEqualObjects(a.link, @"http://www.nytimes.com/2015/09/05/us/at-west-point-annual-pillow-fight-becomes-weaponized.html?mwrsm=Email&_r=1&pagewanted=all");
XCTAssertEqualObjects(a.guid, @"http://onefoottsunami.com/?p=14863");
XCTAssertEqual(a.datePublished, [NSDate dateWithTimeIntervalSince1970:1441722101]); // 2015-09-08T14:21:41Z
[self measureBlock:^{
NSError *error = nil;
RSParseFeedSync(xmlData, &error);
[[xmlData getParser] parseSync:nil];
}];
}
- (void)testScriptingNews {
RSXMLData *xmlData = [self xmlFile:@"scriptingNews" extension:@"rss"];
XCTAssertEqual(xmlData.parserClass, [RSRSSParser class]);
NSError *error = nil;
RSXMLData *xmlData = [[self class] scriptingNewsData];
RSParsedFeed *parsedFeed = RSParseFeedSync(xmlData, &error);
NSLog(@"parsedFeed: %@", parsedFeed);
RSParsedFeed *parsedFeed = [[xmlData getParser] parseSync:&error];
XCTAssertEqualObjects(parsedFeed.title, @"Scripting News");
XCTAssertEqualObjects(parsedFeed.subtitle, @"Scripting News, the weblog started in 1997 that bootstrapped the blogging revolution...");
XCTAssertEqualObjects(parsedFeed.link, @"http://scripting.com/");
XCTAssertEqual(parsedFeed.articles.count, 25u);
RSParsedArticle *a = parsedFeed.articles.firstObject;
XCTAssertEqualObjects(a.title, @"People don't click links, that's why the 140-char limit will cripple Twitter");
XCTAssertEqualObjects(a.link, @"http://scripting.com/2015/09/08/peopleDontClickLinks.html");
XCTAssertEqualObjects(a.guid, @"http://scripting.com/2015/09/08/peopleDontClickLinks.html");
XCTAssertEqual(a.datePublished, [NSDate dateWithTimeIntervalSince1970:1441723501]); // Tue Sep 8 16:45:01 2015
[self measureBlock:^{
[[xmlData getParser] parseSync:nil];
}];
}
- (void)testManton {
RSXMLData *xmlData = [self xmlFile:@"manton" extension:@"rss"];
XCTAssertEqual(xmlData.parserClass, [RSRSSParser class]);
NSError *error = nil;
RSXMLData *xmlData = [[self class] mantonData];
RSParsedFeed *parsedFeed = RSParseFeedSync(xmlData, &error);
NSLog(@"parsedFeed: %@", parsedFeed);
RSParsedFeed *parsedFeed = [[xmlData getParser] parseSync:&error];
XCTAssertEqualObjects(parsedFeed.title, @"Manton Reece");
XCTAssertNil(parsedFeed.subtitle);
XCTAssertEqualObjects(parsedFeed.link, @"http://www.manton.org");
XCTAssertEqual(parsedFeed.articles.count, 10u);
RSParsedArticle *a = parsedFeed.articles.firstObject;
XCTAssertNil(a.title);
XCTAssertEqualObjects(a.link, @"http://www.manton.org/2015/09/3071.html");
XCTAssertEqualObjects(a.guid, @"http://www.manton.org/?p=3071");
XCTAssertEqual(a.datePublished, [NSDate dateWithTimeIntervalSince1970:1443191200]); // Fri, 25 Sep 2015 14:26:40 +0000
[self measureBlock:^{
[[xmlData getParser] parseSync:nil];
}];
}
- (void)testKatieFloyd {
RSXMLData *xmlData = [self xmlFile:@"KatieFloyd" extension:@"rss"];
XCTAssertEqual(xmlData.parserClass, [RSRSSParser class]);
NSError *error = nil;
RSXMLData *xmlData = [[self class] katieFloydData];
RSParsedFeed *parsedFeed = RSParseFeedSync(xmlData, &error);
RSParsedFeed *parsedFeed = [[xmlData getParser] parseSync:&error];
XCTAssertEqualObjects(parsedFeed.title, @"Katie Floyd");
XCTAssertNil(parsedFeed.subtitle);
XCTAssertEqualObjects(parsedFeed.link, @"http://www.katiefloyd.com");
XCTAssertEqual(parsedFeed.articles.count, 20u);
RSParsedArticle *a = parsedFeed.articles.firstObject;
XCTAssertEqualObjects(a.title, @"Special Mac Power Users for Relay FM Members");
XCTAssertEqualObjects(a.link, @"http://tracking.feedpress.it/link/980/4243452");
XCTAssertEqualObjects(a.guid, @"50c628b3e4b07b56461546c5:50c658a6e4b0cc9aa9ce4405:57bcbe83e4fcb567fdffc020");
XCTAssertEqual(a.datePublished, [NSDate dateWithTimeIntervalSince1970:1472163600]); // Thu, 25 Aug 2016 22:20:00 +0000
[self measureBlock:^{
[[xmlData getParser] parseSync:nil];
}];
}
- (void)testEMarley {
NSError *error = nil;
RSXMLData *xmlData = [[self class] eMarleyData];
RSParsedFeed *parsedFeed = RSParseFeedSync(xmlData, &error);
XCTAssertEqualObjects(parsedFeed.title, @"Stories by Liz Marley on Medium");
XCTAssertEqual(parsedFeed.articles.count, 10u);
}
- (void)testScriptingNewsPerformance {
RSXMLData *xmlData = [[self class] scriptingNewsData];
[self measureBlock:^{
NSError *error = nil;
RSParseFeedSync(xmlData, &error);
}];
}
- (void)testMantonPerformance {
RSXMLData *xmlData = [[self class] mantonData];
[self measureBlock:^{
NSError *error = nil;
RSParseFeedSync(xmlData, &error);
}];
}
- (void)testDaringFireballPerformance {
RSXMLData *xmlData = [[self class] daringFireballData];
[self measureBlock:^{
NSError *error = nil;
RSParseFeedSync(xmlData, &error);
}];
}
- (void)testCanParseFeedPerformance {
RSXMLData *xmlData = [self xmlFile:@"EMarley" extension:@"rss"];
XCTAssertEqual(xmlData.parserClass, [RSRSSParser class]);
NSError *error = nil;
RSParsedFeed *parsedFeed = [[xmlData getParser] parseSync:&error];
XCTAssertEqualObjects(parsedFeed.title, @"Stories by Liz Marley on Medium");
XCTAssertEqualObjects(parsedFeed.subtitle, @"Stories by Liz Marley on Medium");
XCTAssertEqualObjects(parsedFeed.link, @"https://medium.com/@emarley?source=rss-b4981c59ffa5------2");
XCTAssertEqual(parsedFeed.articles.count, 10u);
RSParsedArticle *a = parsedFeed.articles.firstObject;
XCTAssertEqualObjects(a.title, @"UI Automation & screenshots");
XCTAssertEqualObjects(a.link, @"https://medium.com/@emarley/ui-automation-screenshots-c44a41af38d1?source=rss-b4981c59ffa5------2");
XCTAssertEqualObjects(a.guid, @"https://medium.com/p/c44a41af38d1");
XCTAssertEqual(a.datePublished, [NSDate dateWithTimeIntervalSince1970:1462665210]); // Sat, 07 May 2016 23:53:30 GMT
RSXMLData *xmlData = [[self class] daringFireballData];
// 0.379
[self measureBlock:^{
for (NSInteger i = 0; i < 100; i++) {
RSCanParseFeed(xmlData);
}
[[xmlData getParser] parseSync:nil];
}];
}
- (void)testDaringFireball {
RSXMLData *xmlData = [self xmlFile:@"DaringFireball" extension:@"atom"];
XCTAssertEqual(xmlData.parserClass, [RSAtomParser class]);
NSError *error = nil;
RSParsedFeed *parsedFeed = [[xmlData getParser] parseSync:&error];
XCTAssertEqualObjects(parsedFeed.title, @"Daring Fireball");
XCTAssertEqualObjects(parsedFeed.subtitle, @"By John Gruber");
XCTAssertEqualObjects(parsedFeed.link, @"http://daringfireball.net/");
XCTAssertEqual(parsedFeed.articles.count, 47u);
RSParsedArticle *a = parsedFeed.articles.firstObject;
XCTAssertEqualObjects(a.title, @"Apple Product Event: Monday March 21");
XCTAssertEqualObjects(a.link, @"http://recode.net/2016/02/27/remark-your-calendars-apples-product-event-will-week-of-march-21/");
XCTAssertEqualObjects(a.guid, @"tag:daringfireball.net,2016:/linked//6.32173");
XCTAssertEqual(a.datePublished, [NSDate dateWithTimeIntervalSince1970:1456610387]); // 2016-02-27T21:59:47Z
[self measureBlock:^{
[[xmlData getParser] parseSync:nil];
}];
}
#pragma mark - Variety Test & Other
- (void)testDownloadedFeeds {
NSError *error = nil;
int i = 0;
while (true) {
++i;
NSString *pth = [NSString stringWithFormat:@"feed_%d", i];
NSString *s = [[NSBundle bundleForClass:[self class]] pathForResource:pth ofType:@"rss" inDirectory:@"Resources"];
if (s == nil) {
break;
}
NSData *d = [[NSData alloc] initWithContentsOfFile:s];
RSXMLData *xmlData = [[RSXMLData alloc] initWithData:d urlString:pth];
RSParsedFeed *parsedFeed = RSParseFeedSync(xmlData, &error);
printf("\n\nparsing: %s\n%s\n", pth.UTF8String, parsedFeed.description.UTF8String);
RSXMLData *xmlData = [self xmlFile:[NSString stringWithFormat:@"feed_%d", i] extension:@"rss"];
if (!xmlData) break;
RSParsedFeed *parsedFeed = [[xmlData getParser] parseSync:&error];
XCTAssertNil(error);
XCTAssert(parsedFeed);
XCTAssert(parsedFeed.title);
XCTAssert(parsedFeed.link);
XCTAssert(parsedFeed.articles.count > 0);
//printf("\n\nparsing: %s\n%s\n", xmlData.urlString.UTF8String, parsedFeed.description.UTF8String);
}
}
- (void)testDownloadedFeedsPerformance {
[self measureBlock:^{
[self testDownloadedFeeds];
}];
}
- (void)testSingle {
NSError *error = nil;
NSString *filename = @"feed_1";
NSString *s = [[NSBundle bundleForClass:[self class]] pathForResource:filename ofType:@"rss" inDirectory:@"Resources"];
NSData *d = [[NSData alloc] initWithContentsOfFile:s];
RSXMLData *xmlData = [[RSXMLData alloc] initWithData:d urlString:@"single-feed"];
RSParsedFeed *parsedFeed = RSParseFeedSync(xmlData, &error);
printf("\n\nparsing: %s\n%s\n", filename.UTF8String, parsedFeed.description.UTF8String);
RSXMLData *xmlData = [self xmlFile:@"feed_1" extension:@"rss"];
RSParsedFeed *parsedFeed = [[xmlData getParser] parseSync:&error];
printf("\n\nparsing: %s\n%s\n", xmlData.urlString.UTF8String, parsedFeed.description.UTF8String);
XCTAssertNil(error);
}
- (void)testDetermineParserClassPerformance {
RSXMLData *xmlData = [self xmlFile:@"DaringFireball" extension:@"atom"];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
[self measureBlock:^{
for (NSInteger i = 0; i < 100; i++) {
[xmlData performSelector:@selector(determineParserClass)];
}
}];
#pragma clang diagnostic pop
}
@end

View File

@@ -1,31 +0,0 @@
class SomeViewController: NSViewController {
@IBOutlet weak var textField: NSTextField
private var NSTimer: fetchDataTimer?
private var currentText: String? {
didSet {
invalidateTimer()
if currentText.length > 3 {
restartTimer()
}
}
}
func textDidChange(notification: NSNotification) {
currentText = textField.stringValue
}
func invalidateTimer() {
if let timer = timer {
if timer.isValid {
timer.invalidate()
}
self.timer = nil
}
}
}