| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437 |
- /**
- * https://github.com/tadija/AEXML
- * Copyright © Marko Tadić 2014-2020
- * Licensed under the MIT license
- */
- import Foundation
- #if canImport(FoundationXML)
- import FoundationXML
- #endif
- import XCTest
- @testable import XML
- class XMLTests: XCTestCase {
-
- // MARK: - Properties
-
- var exampleDocument = Document()
- var plantsDocument = Document()
-
- // MARK: - Helpers
-
- func URLForResource(fileName: String, withExtension ext: String) -> URL {
- guard let url = Bundle.module.url(forResource: fileName, withExtension: ext) else {
- fatalError("can't find resource named: '\(fileName)'")
- }
- return url
- }
-
- func xmlDocumentFromURL(url: URL) -> Document {
- var xmlDocument = Document()
-
- do {
- let data = try Data.init(contentsOf: url)
- xmlDocument = try Document(xml: data)
- } catch {
- print(error)
- }
-
- return xmlDocument
- }
-
- func readXMLFromFile(filename: String) -> Document {
- let url = URLForResource(fileName: filename, withExtension: "xml")
- return xmlDocumentFromURL(url: url)
- }
-
- // MARK: - Setup & Teardown
-
- override func setUp() {
- super.setUp()
-
- // create some sample xml documents
- exampleDocument = readXMLFromFile(filename: "example")
- plantsDocument = readXMLFromFile(filename: "plant_catalog")
- }
-
- override func tearDown() {
- // reset sample xml document
- exampleDocument = Document()
- plantsDocument = Document()
-
- super.tearDown()
- }
-
- // MARK: - XML Document
-
- func testXMLDocumentManualDataLoading() {
- do {
- let url = URLForResource(fileName: "example", withExtension: "xml")
- let data = try Data.init(contentsOf: url)
-
- let testDocument = Document()
- try testDocument.load(data)
- XCTAssertEqual(testDocument.root.name, "animals", "Should be able to find root element.")
- } catch {
- XCTFail("Should be able to load XML Document with given Data.")
- }
- }
-
- func testXMLDocumentInitFromString() {
- do {
- let testDocument = try Document(xml: exampleDocument.xml)
- XCTAssertEqual(testDocument.xml, exampleDocument.xml)
- } catch {
- XCTFail("Should be able to initialize XML Document from XML String.")
- }
- }
-
- func testXMLOptions() {
- do {
- var options = Options()
- options.documentHeader.version = 2.0
- options.documentHeader.encoding = "utf-16"
- options.documentHeader.standalone = "yes"
-
- let testDocument = try Document(xml: "<foo><bar>hello</bar></foo>", options: options)
- XCTAssertEqual(testDocument.xml, "<?xml version=\"2.0\" encoding=\"utf-16\" standalone=\"yes\"?>\n<foo>\n\t<bar>hello</bar>\n</foo>")
- XCTAssertEqual(try testDocument.root.bar.first?.get(), "hello")
- } catch {
- XCTFail("Should be able to initialize XML Document with custom Options.")
- }
- }
-
- func testXMLParser() {
- do {
- let testDocument = Document()
- let url = URLForResource(fileName: "example", withExtension: "xml")
- let data = try Data.init(contentsOf: url)
-
- let parser = Parser(document: testDocument, data: data)
- try parser.parse()
-
- XCTAssertEqual(testDocument.root.name, "animals", "Should be able to find root element.")
- } catch {
- XCTFail("Should be able to parse XML Data into XML Document without throwing error.")
- }
- }
-
- func testXMLParserTrimsWhitespace() {
- let result = whitespaceResult(shouldTrimWhitespace: true)
- XCTAssertEqual(result, "Hello,")
- }
-
- func testXMLParserWithoutTrimmingWhitespace() {
- let result = whitespaceResult(shouldTrimWhitespace: false)
- XCTAssertEqual(result, "Hello, ")
- }
-
- private func whitespaceResult(shouldTrimWhitespace: Bool) -> String? {
- do {
- var options = Options()
- options.parserSettings.shouldTrimWhitespace = shouldTrimWhitespace
-
- let testDocument = Document(options: options)
- let url = URLForResource(fileName: "whitespace_examples", withExtension: "xml")
- let data = try Data.init(contentsOf: url)
-
- let parser = Parser(document: testDocument, data: data)
- try parser.parse()
-
- return testDocument.root.text.first?.value
- } catch {
- XCTFail("Should be able to parse XML without throwing an error")
- }
- return nil
- }
-
- func testXMLParserError() {
- do {
- let testDocument = Document()
- let testData = Data()
- let parser = Parser(document: testDocument, data: testData)
- try parser.parse()
- } catch {
- XCTAssertEqual(error.localizedDescription, XMLError.parsingFailed.localizedDescription)
- }
- }
-
- // MARK: - XML Read
-
- func testRootElement() {
- XCTAssertEqual(exampleDocument.root.name, "animals", "Should be able to find root element.")
-
- let documentWithoutRootElement = Document()
- let rootElement = documentWithoutRootElement.root
- XCTAssertEqual(rootElement.error, XMLError.rootElementMissing, "Should have RootElementMissing error.")
- }
-
- func testParentElement() {
- XCTAssertEqual(exampleDocument.root.cats.parent?.name, "animals", "Should be able to find parent element.")
- }
-
- func testChildrenElements() {
- var count = 0
- for _ in exampleDocument.root.cats.children {
- count += 1
- }
- XCTAssertEqual(count, 4, "Should be able to iterate children elements")
- }
-
- func testName() {
- let secondChildElementName = exampleDocument.root.children[1].name
- XCTAssertEqual(secondChildElementName, "dogs", "Should be able to return element name.")
- }
-
- func testAttributes() {
- let firstCatAttributes = exampleDocument.root.cats.cat.attributes
- XCTAssertEqual(firstCatAttributes["breed"], "Siberian", "Should be able to return attribute value.")
- }
-
- func testValue() {
- let firstPlant = plantsDocument.root.PLANT
- XCTAssertEqual(firstPlant.COMMON, "Bloodroot", "Should be able to return element value as optional string.")
- XCTAssertNil(firstPlant.ELEMENTWITHOUTVALUE.value, "Should be able to have nil value.")
- XCTAssertNil(firstPlant.EMPTYELEMENT.value, "Should be able to have nil value.")
- }
-
- func testStringValue() {
- let firstPlant = plantsDocument.root.PLANT
- XCTAssertEqual(firstPlant.COMMON.value, "Bloodroot", "Should be able to return element value as string.")
- XCTAssertNil(firstPlant.ELEMENTWITHOUTVALUE.value, "Should be able to return nil if element has no value.")
- XCTAssertNil(firstPlant.EMPTYELEMENT.value, "Should be able to return nil if element has no value.")
- }
-
- func testBoolValue() {
- XCTAssertEqual(plantsDocument.root.PLANT.TRUESTRING, true, "Should be able to cast element value as Bool.")
- XCTAssertEqual(plantsDocument.root.PLANT.FALSESTRING, false, "Should be able to cast element value as Bool.")
- // XCTAssertEqual(plantsDocument.root.PLANT.TRUESTRING2, true, "Should be able to cast element value as Bool.")
- // XCTAssertEqual(plantsDocument.root.PLANT.FALSESTRING2, false, "Should be able to cast element value as Bool.")
- // XCTAssertEqual(plantsDocument.root.PLANT.TRUEINT, true, "Should be able to cast element value as Bool.")
- // XCTAssertEqual(plantsDocument.root.PLANT.FALSEINT, false, "Should be able to cast element value as Bool.")
- XCTAssertNil(plantsDocument.root.ELEMENTWITHOUTVALUE as Bool?, "Should be able to return nil if value can't be represented as Bool.")
- }
-
- func testIntValue() throws {
- XCTAssertEqual(plantsDocument.root.PLANT.ZONE, 4, "Should be able to cast element value as Integer.")
- XCTAssertNil(plantsDocument.root.PLANT.ELEMENTWITHOUTVALUE as Int?, "Should be able to return nil if value can't be represented as Integer.")
- }
-
- func testDoubleValue() throws {
- XCTAssertEqual(plantsDocument.root.PLANT.PRICE, 2.44, "Should be able to cast element value as Double.")
- XCTAssertNil(plantsDocument.root.PLANT.ELEMENTWITHOUTVALUE as Double?, "Should be able to return nil if value can't be represented as Double.")
- }
- func testNotExistingElement() throws {
- // non-optional
- XCTAssertNotNil(exampleDocument.root.ducks.duck.error, "Should contain error inside element which does not exist.")
- XCTAssertEqual(exampleDocument.root.ducks.duck.error, XMLError.elementNotFound, "Should have ElementNotFound error.")
- XCTAssertNil(exampleDocument.root.ducks.duck.value, "Should have empty value.")
- XCTAssertNil(exampleDocument.root.ducks.duck.first, "Should not be able to find ducks here.")
- }
- func testAllElements() {
- var count = 0
- if let cats = exampleDocument.root.cats.cat.all {
- for cat in cats {
- XCTAssertNotNil(cat.parent, "Each child element should have its parent element.")
- count += 1
- }
- }
- XCTAssertEqual(count, 4, "Should be able to iterate all elements")
- }
-
- func testFirstElement() throws {
- let catElement = exampleDocument.root.cats.cat
- let firstCatExpectedValue = "Tinna"
-
- // non-optional
- XCTAssertEqual(try catElement.get(), firstCatExpectedValue, "Should be able to find the first element as non-optional.")
-
- // optional
- if let cat = catElement.first {
- XCTAssertEqual(try cat.get(), firstCatExpectedValue, "Should be able to find the first element as optional.")
- } else {
- XCTFail("Should be able to find the first element.")
- }
- }
-
- func testLastElement() throws {
- if let dog = exampleDocument.root.dogs.dog.last {
- XCTAssertEqual(try dog.get(), "Kika", "Should be able to find the last element.")
- } else {
- XCTFail("Should be able to find the last element.")
- }
- }
-
- func testCountElements() {
- let dogsCount = exampleDocument.root.dogs.dog.count
- XCTAssertEqual(dogsCount, 4, "Should be able to count elements.")
- }
-
- func testAllWithValue() {
- let cats = exampleDocument.root.cats
- cats.addChild(name: "cat", value: "Tinna")
-
- var count = 0
- if let tinnas = cats["cat"].all(withValue: "Tinna") {
- for _ in tinnas {
- count += 1
- }
- }
- XCTAssertEqual(count, 2, "Should be able to return elements with given value.")
- }
-
- func testAllWithAttributes() {
- var count = 0
- if let bulls = exampleDocument.root.dogs.dog.all(withAttributes: ["color" : "white"]) {
- for _ in bulls {
- count += 1
- }
- }
- XCTAssertEqual(count, 2, "Should be able to return elements with given attributes.")
- }
-
- func testAllContainingAttributes() {
- var count = 0
- if let bulls = exampleDocument.root.dogs.dog.all(containingAttributeKeys: ["gender"]) {
- for _ in bulls {
- count += 1
- }
- }
- XCTAssertEqual(count, 2, "Should be able to return elements with given attribute keys.")
- }
-
- func testAllDescendantsWherePredicate() {
- let children = exampleDocument.allDescendants { $0.attributes["color"] == "yellow" }
-
- XCTAssertEqual(children.count, 2, "Should be able to return elements matching predicate.")
- }
-
- func testFirstDescendantWherePredicate() {
- let descendant = plantsDocument.root.firstDescendant { $0.hasDescendant { $0.name == "LIGHT" && $0.value == "Sunny" } }
- let plantName = descendant?["COMMON"].value
-
- XCTAssertEqual(plantName, "Black-Eyed Susan", "Should be able to find first child satisfying predicate.")
- }
-
- func testHasDescendantWherePredicate() throws {
- let hasDescendant = plantsDocument.hasDescendant { $0.name == "AVAILABILITY" && $0.value == "030699" }
- XCTAssert(hasDescendant, "Should be able to determine that document has a child satisfying predicate.")
- }
-
- func testSpecialCharacterTrimRead() {
- let expected = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n<elements>\n\t<string name=\"this_and_that\">This & that</string>\n</elements>"
-
- let readerDocument = try! Document(xml: expected)
- let readerXml = readerDocument.xml
- XCTAssertEqual(readerXml, expected, "Should be able to print XML formatted string.")
- }
-
- // MARK: - XML Write
-
- func testAddChild() throws {
- let ducks = exampleDocument.root.addChild(name: "ducks")
- ducks.addChild(name: "duck", value: "Donald")
- ducks.addChild(name: "duck", value: "Daisy")
- ducks.addChild(name: "duck", value: "Scrooge")
-
- let animalsCount = exampleDocument.root.children.count
- XCTAssertEqual(animalsCount, 3, "Should be able to add child elements to an element.")
- XCTAssertEqual(try exampleDocument.root["ducks"]["duck"].last?.get(), "Scrooge", "Should be able to iterate ducks now.")
- }
-
- func testAddChildWithAttributes() throws {
- let cats = exampleDocument.root.cats
- let dogs = exampleDocument.root.dogs
-
- cats.addChild(name: "cat", value: "Garfield", attributes: ["breed" : "tabby", "color" : "orange"])
- dogs.addChild(name: "dog", value: "Snoopy", attributes: ["breed" : "beagle", "color" : "white"])
-
- let catsCount = cats["cat"].count
- let dogsCount = dogs["dog"].count
-
- let lastCat = cats["cat"].last!
- let penultDog = dogs.children[3]
-
- XCTAssertEqual(catsCount, 5, "Should be able to add child element with attributes to an element.")
- XCTAssertEqual(dogsCount, 5, "Should be able to add child element with attributes to an element.")
-
- XCTAssertEqual(lastCat.attributes["color"], "orange", "Should be able to get attribute value from added element.")
- XCTAssertEqual(try penultDog.get(), "Kika", "Should be able to add child with attributes without overwrites existing elements. (Github Issue #28)")
- }
-
- func testAddChildren() {
- let animals: [Element] = [
- Element(name: "dinosaurs"),
- Element(name: "birds"),
- Element(name: "bugs"),
- ]
- exampleDocument.root.addChildren(animals)
-
- let animalsCount = exampleDocument.root.children.count
- XCTAssertEqual(animalsCount, 5, "Should be able to add children elements to an element.")
- }
-
- func testAddAttributes() {
- let firstCat = exampleDocument.root.cats.cat
- firstCat.attributes["funny"] = "true"
- firstCat.attributes["speed"] = "fast"
- firstCat.attributes["years"] = "7"
-
- XCTAssertEqual(firstCat.attributes.count, 5, "Should be able to add attributes to an element.")
- XCTAssertEqual(Int(firstCat.attributes["years"]!), 7, "Should be able to get any attribute value now.")
- }
-
- func testRemoveChild() throws {
- let cats = exampleDocument.root.cats
- let lastCat = cats["cat"].last!
- let duplicateCat = cats.addChild(name: "cat", value: "Tinna", attributes: ["breed" : "Siberian", "color" : "lightgray"])
-
- lastCat.removeFromParent()
- duplicateCat.removeFromParent()
-
- let catsCount = cats["cat"].count
- let firstCat = cats["cat"]
- XCTAssertEqual(catsCount, 3, "Should be able to remove element from parent.")
- XCTAssertEqual(try firstCat.get(), "Tinna", "Should be able to remove the exact element from parent.")
- }
-
- func testXMLEscapedString() {
- let string = "&<>'\""
- let escapedString = string.xmlEscaped
- XCTAssertEqual(escapedString, "&<>'"")
- }
-
- func testXMLString() {
- let testDocument = Document()
- let children = testDocument.addChild(name: "children")
- children.addChild(name: "child", value: "value", attributes: ["attribute" : "attributeValue<&>"])
- children.addChild(name: "child")
- children.addChild(name: "child", value: "&<>'\"")
-
- XCTAssertEqual(testDocument.xml, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n<children>\n\t<child attribute=\"attributeValue<&>\">value</child>\n\t<child />\n\t<child>&<>'"</child>\n</children>", "Should be able to print XML formatted string.")
-
- XCTAssertEqual(testDocument.xmlCompact, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?><children><child attribute=\"attributeValue<&>\">value</child><child /><child>&<>'"</child></children>", "Should be able to print compact XML string.")
-
- XCTAssertEqual(testDocument.xmlSpaces, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n<children>\n <child attribute=\"attributeValue<&>\">value</child>\n <child />\n <child>&<>'"</child>\n</children>", "Should be able to print XML formatted string.")
- }
-
- // MARK: - XML Parse Performance
-
- func testReadXMLPerformance() {
- self.measure() {
- _ = self.readXMLFromFile(filename: "plant_catalog")
- }
- }
-
- func testWriteXMLPerformance() {
- self.measure() {
- _ = self.plantsDocument.xml
- }
- }
-
- }
|