Skip to content
This repository has been archived by the owner on Feb 3, 2020. It is now read-only.

Commit

Permalink
Merge branch 'feature/message_with_type'
Browse files Browse the repository at this point in the history
  • Loading branch information
Bouke committed Jan 30, 2017
2 parents fef12cb + a15409f commit 68d6fde
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 14 deletions.
17 changes: 8 additions & 9 deletions Sources/CodeGenerator/Schema+toSwift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,25 +102,24 @@ extension Service {

let name = "\(self.name.localName.toSwiftTypeName())Client"

// types.first!.value.name

// returns the message's {input,output} type and corresponding type identifier
let message = { (messageName: QualifiedName) -> (QualifiedName, Identifier) in
let message = webService.messages.first { $0.name == messageName }!
let element = message.parts.first!.element
return (element, types[.element(element)]!.name)
if let element = message.parts.first!.element {
return (element, types[.element(element)]!.name)
} else if let type = message.parts.first!.type {
return (type, types[.type(type)]!.name)
} else {
fatalError("Unsupported element message type")
}
}

//TODO: zip operations first; combinding port.operation and binding.operation
let methods = portType.operations
.map { operation in (port: operation, binding: binding.operations.first(where: { $0.name == operation.name })!) }
.map { operation -> ServiceMethod in
// let inputMessage = webService.messages.first { $0.name == operation.port.inputMessage }!
// let inputElement = input.parts.first!.element
// let input = (inputElement, types[.element(inputElement)]!)
// let output = webService.messages.first { $0.name == operation.port.outputMessage }!
let input = message(operation.port.inputMessage)
let output = message(operation.port.outputMessage)

return ServiceMethod(operation: operation.port, input: input, output: output, action: operation.binding.action)
}

Expand Down
20 changes: 17 additions & 3 deletions Sources/CodeGenerator/WebServiceDescription+verify.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ extension WebServiceDescription {
typealias Graph = CodeGenerator.Graph<Node>
typealias Edge = (from: Node, to: Node)

/// Verifies whether all type references are valid. It will construct a
/// graph having edges for all references and nodes for all types. The set
/// of missing nodes is calculated by comparing the actual nodes with the
/// references nodes. The set of base XML Schema types are subtracted. If
/// the remaining set of missing nodes is greater then 0, an error will be
/// thrown.
///
/// - Throws: WebServiceDescriptionVerifyError.missingNodes(Set<Node>)
public func verify() throws {
var nodes = Set<Node>()
var edges: [Edge] = []
Expand Down Expand Up @@ -51,9 +59,15 @@ extension WebServiceDescription {

nodes.formUnion(messages.map { .message($0.name) })
edges.append(contentsOf: messages
.flatMap { message in
message.parts.map { part in
(from: .message(message.name), to: .element(part.element))
.flatMap { message -> [Edge] in
message.parts.flatMap { part -> Edge? in
if let element = part.element {
return (from: .message(message.name), to: .element(element))
} else if let type = part.type {
return (from: .message(message.name), to: .type(type))
} else {
return nil
}
}
}
)
Expand Down
6 changes: 4 additions & 2 deletions Sources/SchemaParser/WebServiceDescription.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import Lark
public struct Message {
public struct Part {
public let name: QualifiedName
public let element: QualifiedName
public let element: QualifiedName?
public let type: QualifiedName?

init(deserialize element: XMLElement) throws {
self.name = QualifiedName(uri: try targetNamespace(ofNode: element), localName: element.attribute(forName: "name")!.stringValue!)
self.element = try QualifiedName(type: element.attribute(forName: "element")!.stringValue!, inTree: element)
self.element = try element.attribute(forName: "element")?.stringValue.flatMap({ try QualifiedName(type: $0, inTree: element) })
self.type = try element.attribute(forName: "type")?.stringValue.flatMap({ try QualifiedName(type: $0, inTree: element) })
}
}

Expand Down
7 changes: 7 additions & 0 deletions Tests/CodeGeneratorTests/CodeGeneratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,11 @@ class CodeGeneratorTests: XCTestCase {
let expected = try readlines("nillable_array.txt")
XCTAssertCode(actual: try schema.generateCode(), expected: expected)
}

func testMessageWithType() throws {
let webService = try deserializeWebServiceDescription("message_with_type.wsdl")
let expected = try readlines("message_with_type.txt")
let actual = try generate(webService: webService, service: webService.services.first!).components(separatedBy: "\n")
XCTAssertCode(actual: actual, expected: expected)
}
}
5 changes: 5 additions & 0 deletions Tests/CodeGeneratorTests/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ func deserialize(_ input: String) throws -> Schema {
return try parseSchema(contentsOf: url)
}

func deserializeWebServiceDescription(_ input: String) throws -> WebServiceDescription {
let url = URL(fileURLWithPath: #file).deletingLastPathComponent().appendingPathComponent("Inputs").appendingPathComponent(input)
return try parseWebServiceDefinition(contentsOf: url)
}

func readlines(_ input: String) throws -> [String] {
let url = URL(fileURLWithPath: #file).deletingLastPathComponent().appendingPathComponent("Inputs").appendingPathComponent(input)
return Array(try String(contentsOf: url).components(separatedBy: "\n").dropLast())
Expand Down
14 changes: 14 additions & 0 deletions Tests/CodeGeneratorTests/WebServiceDescription+verifyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class WebServiceDescriptionVerifyTests: XCTestCase {
let webService = try deserialize("missing_binding.wsdl")
do {
try webService.verify()
XCTFail("Should not verified")
} catch WebServiceDescriptionVerifyError.missingNodes(let nodes) {
XCTAssertEqual(nodes, [.binding(QualifiedName(uri: "http://tempuri.org/", localName: "ImportSoapBinding"))])
} catch {
Expand All @@ -35,10 +36,23 @@ class WebServiceDescriptionVerifyTests: XCTestCase {
let webService = try deserialize("missing_port.wsdl")
do {
try webService.verify()
XCTFail("Should not verified")
} catch WebServiceDescriptionVerifyError.missingNodes(let nodes) {
XCTAssertEqual(nodes, [.port(QualifiedName(uri: "http://tempuri.org/", localName: "ImportSoapType"))])
} catch {
XCTFail("Failed with error: \(error)")
}
}

func testMissingMessageType() throws {
let webService = try deserialize("missing_message_type.wsdl")
do {
try webService.verify()
XCTFail("Should not verified")
} catch WebServiceDescriptionVerifyError.missingNodes(let nodes) {
XCTAssertEqual(nodes, [.type(QualifiedName(uri: "http://tempuri.org/", localName: "MissingType"))])
} catch {
XCTFail("Failed with error: \(error)")
}
}
}
53 changes: 53 additions & 0 deletions Tests/SchemaParserTests/Inputs/message_with_type.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// This file was generated by Lark. https://github.com/Bouke/Lark

import Alamofire
import Foundation
import Lark

//
// MARK: - SOAP Structures
//


//
// MARK: - SOAP Client
//
class TestClient: Client {
static let defaultEndpoint = URL(string: "http://localhost")!
override init(endpoint: URL = TestClient.defaultEndpoint, sessionManager: SessionManager = SessionManager()) {
super.init(endpoint: endpoint, sessionManager: sessionManager)
}
@discardableResult func test(_ parameter: String) throws -> String {
let response = try call(
action: URL(string: "")!,
serialize: { envelope in
let node = XMLElement(prefix: "ns0", localName: "string", uri: "http://www.w3.org/2001/XMLSchema")
node.addNamespace(XMLNode.namespace(withName: "ns0", stringValue: "http://www.w3.org/2001/XMLSchema") as! XMLNode)
try parameter.serialize(node)
envelope.body.addChild(node)
return envelope
},
deserialize: { envelope -> String in
let node = envelope.body.elements(forLocalName: "string", uri: "http://www.w3.org/2001/XMLSchema").first!
return try String(deserialize: node)
})
return try response.result.resolve()
}
@discardableResult func testAsync(_ parameter: String, completionHandler: @escaping (Result<String>) -> Void) -> DataRequest {
return callAsync(
action: URL(string: "")!,
serialize: { envelope in
let node = XMLElement(prefix: "ns0", localName: "string", uri: "http://www.w3.org/2001/XMLSchema")
node.addNamespace(XMLNode.namespace(withName: "ns0", stringValue: "http://www.w3.org/2001/XMLSchema") as! XMLNode)
try parameter.serialize(node)
envelope.body.addChild(node)
return envelope
},
deserialize: { envelope in
let node = envelope.body.elements(forLocalName: "string", uri: "http://www.w3.org/2001/XMLSchema").first!
return try String(deserialize: node)
},
completionHandler: completionHandler)
}
}

28 changes: 28 additions & 0 deletions Tests/SchemaParserTests/Inputs/message_with_type.wsdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<definitions xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://tempuri.org/" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://tempuri.org/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<message name="Message">
<part name="echo" type="xs:string"/>
</message>
<portType name="Test">
<operation name="Test">
<input message="tns:Message"/>
<output message="tns:Message"/>
</operation>
</portType>
<binding name="Test" type="tns:Test">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="Test">
<soap:operation soapAction="" style="document"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="Test">
<port name="Test" binding="tns:Test">
<soap:address location="http://localhost"/>
</port>
</service>
</definitions>
28 changes: 28 additions & 0 deletions Tests/SchemaParserTests/Inputs/missing_message_type.wsdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<definitions xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://tempuri.org/" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://tempuri.org/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<message name="Message">
<part name="echo" type="tns:MissingType"/>
</message>
<portType name="Test">
<operation name="Test">
<input message="tns:Message"/>
<output message="tns:Message"/>
</operation>
</portType>
<binding name="Test" type="tns:Test">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="Test">
<soap:operation soapAction="" style="document"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="Test">
<port name="Test" binding="tns:Test">
<soap:address location="http://localhost"/>
</port>
</service>
</definitions>
10 changes: 10 additions & 0 deletions Tests/SchemaParserTests/WebServiceDescriptionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,14 @@ class WebServiceDescriptionTests: XCTestCase {
XCTFail("Parse error: \(error)")
}
}

func testMessageWithType() {
do {
let webService = try deserialize("message_with_type.wsdl")
XCTAssertNil(webService.messages.first?.parts.first?.element)
XCTAssertNotNil(webService.messages.first?.parts.first?.type)
} catch {
XCTFail("Parse error: \(error)")
}
}
}

0 comments on commit 68d6fde

Please sign in to comment.