diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1a78ff02..54ab0852 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,10 +2,10 @@ name: Tests on: push: - branches: [ master ] + branches: [ main ] paths-ignore: [ README.md ] pull_request: - branches: [ master ] + branches: [ main ] paths-ignore: [ README.md ] workflow_dispatch: diff --git a/Sources/GraphQL/Error/SyntaxError.swift b/Sources/GraphQL/Error/SyntaxError.swift index 7f2330a2..26f2eb75 100644 --- a/Sources/GraphQL/Error/SyntaxError.swift +++ b/Sources/GraphQL/Error/SyntaxError.swift @@ -50,16 +50,19 @@ func highlightSourceAtLocation(source: Source, location: SourceLocation) -> Stri func splitLines(string: String) -> [String] { - let nsstring = NSString(string: string) - let regex = try! NSRegularExpression(pattern: "\r\n|[\n\r]", options: []) - var lines: [String] = [] var location = 0 - - for match in regex.matches(in: string, options: [], range: NSRange(0.. EventLoopFuture in guard let error = error as? GraphQLError else { - fatalError() + return exeContext.eventLoopGroup.next().makeFailedFuture(error) } exeContext.append(error: error) return exeContext.eventLoopGroup.next().makeSucceededFuture(nil) @@ -809,7 +809,7 @@ func completeValueCatchingError( exeContext.append(error: error) return exeContext.eventLoopGroup.next().makeSucceededFuture(nil) } catch { - fatalError() + return exeContext.eventLoopGroup.next().makeFailedFuture(error) } } @@ -1195,7 +1195,7 @@ func getFieldDef( schema: GraphQLSchema, parentType: GraphQLObjectType, fieldName: String -) -> GraphQLFieldDefinition { +) throws -> GraphQLFieldDefinition { if fieldName == SchemaMetaFieldDef.name && schema.queryType.name == parentType.name { return SchemaMetaFieldDef } else if fieldName == TypeMetaFieldDef.name && schema.queryType.name == parentType.name { @@ -1203,7 +1203,10 @@ func getFieldDef( } else if fieldName == TypeNameMetaFieldDef.name { return TypeNameMetaFieldDef } - - // we know this field exists because we passed validation before execution - return parentType.fields[fieldName]! + + // This field should exist because we passed validation before execution + guard let fieldDefinition = parentType.fields[fieldName] else { + throw GraphQLError(message: "Expected field definition not found: '\(fieldName)' on '\(parentType.name)'") + } + return fieldDefinition } diff --git a/Sources/GraphQL/GraphQL.swift b/Sources/GraphQL/GraphQL.swift index 5cd7cb7e..b4c32870 100644 --- a/Sources/GraphQL/GraphQL.swift +++ b/Sources/GraphQL/GraphQL.swift @@ -33,8 +33,11 @@ public struct GraphQLResult : Equatable, Codable, CustomStringConvertible { } public var description: String { - let data = try! GraphQLJSONEncoder().encode(self) - return String(data: data, encoding: .utf8)! + guard let data = try? GraphQLJSONEncoder().encode(self), + let dataString = String(data: data, encoding: .utf8) else { + return "Unable to encode GraphQLResult" + } + return dataString } } diff --git a/Sources/GraphQL/Language/Lexer.swift b/Sources/GraphQL/Language/Lexer.swift index 0501aa74..f476b26c 100644 --- a/Sources/GraphQL/Language/Lexer.swift +++ b/Sources/GraphQL/Language/Lexer.swift @@ -35,8 +35,9 @@ func advanceLexer(lexer: Lexer) throws -> Token { if token.kind != .eof { repeat { - token.next = try readToken(lexer: lexer, prev: token) - token = token.next! + let nextToken = try readToken(lexer: lexer, prev: token) + token.next = nextToken + token = nextToken } while token.kind == .comment lexer.token = token @@ -608,7 +609,14 @@ func readString(source: Source, start: Int, line: Int, col: Int, prev: Token) th positionIndex = body.utf8.index(after: positionIndex) if code == 92 { // \ - value += String(body.utf8[chunkStartIndex.. SourceLocation { var line = 1 var column = position + 1 - let regex = try! NSRegularExpression(pattern: "\r\n|[\n\r]", options: []) - - let matches = regex.matches(in: source.body, options: [], range: NSRange(0.. Type { */ func parseName(lexer: Lexer) throws -> Name { let token = try expect(lexer: lexer, kind: .name) + guard let value = token.value else { + throw GraphQLError(message: "Expected name token to have value: \(token)") + } return Name( loc: loc(lexer: lexer, startToken: token), - value: token.value! + value: value ) } @@ -172,8 +175,10 @@ func parseDefinition(lexer: Lexer) throws -> Definition { } if peek(lexer: lexer, kind: .name) { - switch lexer.token.value! { - // Note: subscription is an experimental non-spec addition. + guard let value = lexer.token.value else { + throw GraphQLError(message: "Expected name token to have value: \(lexer.token)") + } + switch value { case "query", "mutation", "subscription": return try parseOperationDefinition(lexer: lexer); case "fragment": @@ -236,11 +241,13 @@ func parseOperationDefinition(lexer: Lexer) throws -> OperationDefinition { */ func parseOperationType(lexer: Lexer) throws -> OperationType { let operationToken = try expect(lexer: lexer, kind: .name) + guard let value = operationToken.value else { + throw GraphQLError(message: "Expected name token to have value: \(operationToken)") + } - switch operationToken.value! { + switch value { case "query": return .query case "mutation": return .mutation - // Note: subscription is an experimental non-spec addition. case "subscription": return .subscription default: throw unexpected(lexer: lexer, atToken: operationToken) } @@ -458,26 +465,35 @@ func parseValueLiteral(lexer: Lexer, isConst: Bool) throws -> Value { return try parseObject(lexer: lexer, isConst: isConst) case .int: try lexer.advance() + guard let value = token.value else { + throw GraphQLError(message: "Expected int token to have value: \(token)") + } return IntValue( loc: loc(lexer: lexer, startToken: token), - value: token.value! + value: value ) case .float: try lexer.advance() + guard let value = token.value else { + throw GraphQLError(message: "Expected float token to have value: \(token)") + } return FloatValue( loc: loc(lexer: lexer, startToken: token), - value: token.value! + value: value ) case .string, .blockstring: return try parseStringLiteral(lexer: lexer, startToken: token) case .name: - if (token.value == "true" || token.value == "false") { + guard let value = token.value else { + throw GraphQLError(message: "Expected name token to have value: \(token)") + } + if (value == "true" || value == "false") { try lexer.advance() return BooleanValue( loc: loc(lexer: lexer, startToken: token), - value: token.value == "true" + value: value == "true" ) - } else if token.value == "null" { + } else if value == "null" { try lexer.advance() return NullValue( loc: loc(lexer: lexer, startToken: token) @@ -486,7 +502,7 @@ func parseValueLiteral(lexer: Lexer, isConst: Bool) throws -> Value { try lexer.advance() return EnumValue( loc: loc(lexer: lexer, startToken: token), - value: token.value! + value: value ) } case .dollar: @@ -564,10 +580,13 @@ func parseObjectField(lexer: Lexer, isConst: Bool) throws -> ObjectField { */ func parseStringLiteral(lexer: Lexer, startToken: Token) throws -> StringValue { - try lexer.advance(); + try lexer.advance() + guard let value = startToken.value else { + throw GraphQLError(message: "Expected string literal token to have value: \(startToken)") + } return StringValue( loc: loc(lexer: lexer, startToken: startToken), - value: startToken.value!, + value: value, block: startToken.kind == .blockstring ) } @@ -668,7 +687,10 @@ func parseTypeSystemDefinition(lexer: Lexer) throws -> TypeSystemDefinition { : lexer.token if keywordToken.kind == .name { - switch keywordToken.value! { + guard let value = keywordToken.value else { + throw GraphQLError(message: "Expected keyword token to have value: \(keywordToken)") + } + switch value { case "schema": return try parseSchemaDefinition(lexer: lexer); case "scalar": return try parseScalarTypeDefinition(lexer: lexer); case "type": return try parseObjectTypeDefinition(lexer: lexer); diff --git a/Sources/GraphQL/Map/AnySerialization.swift b/Sources/GraphQL/Map/AnySerialization.swift index 695c074c..da30a51c 100644 --- a/Sources/GraphQL/Map/AnySerialization.swift +++ b/Sources/GraphQL/Map/AnySerialization.swift @@ -6,6 +6,15 @@ public struct AnySerialization { } static func object(with map: Any) throws -> NSObject { - return map as! NSObject + guard let result = map as? NSObject else { + throw EncodingError.invalidValue( + map, + EncodingError.Context( + codingPath: [], + debugDescription: "Expected object input to be castable to NSObject: \(type(of: map))" + ) + ) + } + return result } } diff --git a/Sources/GraphQL/Map/Map.swift b/Sources/GraphQL/Map/Map.swift index 9a471f71..4e8b3d40 100644 --- a/Sources/GraphQL/Map/Map.swift +++ b/Sources/GraphQL/Map/Map.swift @@ -663,7 +663,13 @@ extension Map : Codable { switch self { case .undefined: - fatalError("undefined values should have been excluded from encoding") + throw EncodingError.invalidValue( + self, + EncodingError.Context( + codingPath: [], + debugDescription: "undefined values should have been excluded from encoding" + ) + ) case .null: try container.encodeNil() case let .bool(value): @@ -681,7 +687,15 @@ extension Map : Codable { var container = encoder.container(keyedBy: _DictionaryCodingKey.self) for (key, value) in dictionary { if !value.isUndefined { - let codingKey = _DictionaryCodingKey(stringValue: key)! + guard let codingKey = _DictionaryCodingKey(stringValue: key) else { + throw EncodingError.invalidValue( + self, + EncodingError.Context( + codingPath: [], + debugDescription: "codingKey not found for dictionary key: \(key)" + ) + ) + } try container.encode(value, forKey: codingKey) } } diff --git a/Sources/GraphQL/Map/MapSerialization.swift b/Sources/GraphQL/Map/MapSerialization.swift index 5a2ea022..76779dee 100644 --- a/Sources/GraphQL/Map/MapSerialization.swift +++ b/Sources/GraphQL/Map/MapSerialization.swift @@ -12,13 +12,40 @@ public struct MapSerialization { return .string(string as String) case let array as NSArray: let array: [Map] = try array.map { value in - try self.map(with: value as! NSObject) + guard let value = value as? NSObject else { + throw EncodingError.invalidValue( + array, + EncodingError.Context( + codingPath: [], + debugDescription: "Array value was not an object: \(value) in \(array)" + ) + ) + } + return try self.map(with: value) } return .array(array) case let dictionary as NSDictionary: // Extract from an unordered dictionary, using NSDictionary extraction order let orderedDictionary: OrderedDictionary = try dictionary.reduce(into: [:]) { (dictionary, pair) in - dictionary[pair.key as! String] = try self.map(with: pair.value as! NSObject) + guard let key = pair.key as? String else { + throw EncodingError.invalidValue( + dictionary, + EncodingError.Context( + codingPath: [], + debugDescription: "Dictionary key was not string: \(pair.key) in \(dictionary)" + ) + ) + } + guard let value = pair.value as? NSObject else{ + throw EncodingError.invalidValue( + dictionary, + EncodingError.Context( + codingPath: [], + debugDescription: "Dictionary value was not an object: \(key) in \(dictionary)" + ) + ) + } + dictionary[key] = try self.map(with: value) } return .dictionary(orderedDictionary) default: @@ -35,7 +62,13 @@ public struct MapSerialization { static func object(with map: Map) throws -> NSObject { switch map { case .undefined: - fatalError("undefined values should have been excluded from serialization") + throw EncodingError.invalidValue( + self, + EncodingError.Context( + codingPath: [], + debugDescription: "undefined values should have been excluded from serialization" + ) + ) case .null: return NSNull() case let .bool(value): diff --git a/Sources/GraphQL/Subscription/Subscribe.swift b/Sources/GraphQL/Subscription/Subscribe.swift index d10076c0..b1428a4b 100644 --- a/Sources/GraphQL/Subscription/Subscribe.swift +++ b/Sources/GraphQL/Subscription/Subscribe.swift @@ -178,10 +178,15 @@ func executeSubscription( fields: &inputFields, visitedFragmentNames: &visitedFragmentNames ) - // If query is valid, fields is guaranteed to have at least 1 member - let responseName = fields.keys.first! - let fieldNodes = fields[responseName]! - let fieldNode = fieldNodes.first! + + // If query is valid, fields should have at least 1 member + guard let responseName = fields.keys.first, + let fieldNodes = fields[responseName], + let fieldNode = fieldNodes.first else { + throw GraphQLError( + message: "Subscription field resolution resulted in no field nodes." + ) + } guard let fieldDef = getFieldDef(schema: context.schema, parentType: type, fieldAST: fieldNode) else { throw GraphQLError( diff --git a/Sources/GraphQL/SwiftUtilities/SuggestionList.swift b/Sources/GraphQL/SwiftUtilities/SuggestionList.swift index 9b190adf..cc3aa228 100644 --- a/Sources/GraphQL/SwiftUtilities/SuggestionList.swift +++ b/Sources/GraphQL/SwiftUtilities/SuggestionList.swift @@ -20,6 +20,7 @@ func suggestionList( } return optionsByDistance.keys.sorted { + // Values are guaranteed non-nil since the keys come from the object itself optionsByDistance[$0]! - optionsByDistance[$1]! != 0 } } diff --git a/Sources/GraphQL/Type/Schema.swift b/Sources/GraphQL/Type/Schema.swift index 0fff7452..71a6ea94 100644 --- a/Sources/GraphQL/Type/Schema.swift +++ b/Sources/GraphQL/Type/Schema.swift @@ -108,7 +108,11 @@ public final class GraphQLSchema { public func getImplementations( interfaceType: GraphQLInterfaceType ) -> InterfaceImplementations { - implementations[interfaceType.name]! + guard let matchingImplementations = implementations[interfaceType.name] else { + // If we ask for an interface that hasn't been defined, just return no types. + return InterfaceImplementations.init() + } + return matchingImplementations } // @deprecated: use isSubType instead - will be removed in the future. diff --git a/Sources/GraphQL/Utilities/ASTFromValue.swift b/Sources/GraphQL/Utilities/ASTFromValue.swift index 71095b6e..4009d986 100644 --- a/Sources/GraphQL/Utilities/ASTFromValue.swift +++ b/Sources/GraphQL/Utilities/ASTFromValue.swift @@ -19,9 +19,12 @@ func astFromValue( type: GraphQLInputType ) throws -> Value? { if let type = type as? GraphQLNonNull { - // Note: we're not checking that the result is non-null. - // This function is not responsible for validating the input value. - return try astFromValue(value: value, type: type.ofType as! GraphQLInputType) + guard let nonNullType = type.ofType as? GraphQLInputType else { + throw GraphQLError( + message: "Expected GraphQLNonNull to contain an input type \(type)" + ) + } + return try astFromValue(value: value, type: nonNullType) } guard value != .null else { @@ -31,7 +34,11 @@ func astFromValue( // Convert array to GraphQL list. If the GraphQLType is a list, but // the value is not an array, convert the value using the list's item type. if let type = type as? GraphQLList { - let itemType = type.ofType as! GraphQLInputType + guard let itemType = type.ofType as? GraphQLInputType else { + throw GraphQLError( + message: "Expected GraphQLList to contain an input type \(type)" + ) + } if case .array(let value) = value { var valuesASTs: [Value] = [] @@ -72,7 +79,7 @@ func astFromValue( guard let leafType = type as? GraphQLLeafType else { throw GraphQLError( - message: "Must provide Input Type, cannot use: \(type)" + message: "Expected scalar non-object type to be a leaf type: \(type)" ) } @@ -116,7 +123,11 @@ func astFromValue( } let data = try GraphQLJSONEncoder().encode(Wrapper(map: serialized)) - let string = String(data: data, encoding: .utf8)! + guard let string = String(data: data, encoding: .utf8) else { + throw GraphQLError( + message: "Unable to convert data to utf8 string: \(data)" + ) + } return StringValue(value: String(string.dropFirst(8).dropLast(2))) } diff --git a/Sources/GraphQL/Utilities/NIO+Extensions.swift b/Sources/GraphQL/Utilities/NIO+Extensions.swift index 4f5b200d..89da46b1 100644 --- a/Sources/GraphQL/Utilities/NIO+Extensions.swift +++ b/Sources/GraphQL/Utilities/NIO+Extensions.swift @@ -51,6 +51,7 @@ extension OrderedDictionary where Value : FutureType { return EventLoopFuture.whenAllSucceed(futures, on: eventLoopGroup.next()).map { unorderedResult in var result: OrderedDictionary = [:] for key in keys { + // Unwrap is guaranteed because keys are from original dictionary and maps preserve all elements result[key] = unorderedResult.first(where: { $0.0 == key })!.1 } return result diff --git a/Sources/GraphQL/Utilities/TypeFromAST.swift b/Sources/GraphQL/Utilities/TypeFromAST.swift index 39501ad8..a90cf735 100644 --- a/Sources/GraphQL/Utilities/TypeFromAST.swift +++ b/Sources/GraphQL/Utilities/TypeFromAST.swift @@ -7,6 +7,7 @@ func typeFromAST(schema: GraphQLSchema, inputTypeAST: Type) -> GraphQLType? { if let nonNullType = inputTypeAST as? NonNullType { if let innerType = typeFromAST(schema: schema, inputTypeAST: nonNullType.type) { + // Non-null types by definition must contain nullable types (since all types are nullable by default) return GraphQLNonNull(innerType as! GraphQLNullableType) } } diff --git a/Sources/GraphQL/Utilities/TypeInfo.swift b/Sources/GraphQL/Utilities/TypeInfo.swift index 1483e69c..27ea67bf 100644 --- a/Sources/GraphQL/Utilities/TypeInfo.swift +++ b/Sources/GraphQL/Utilities/TypeInfo.swift @@ -90,8 +90,12 @@ final class TypeInfo { typeStack.append(type) case let node as InlineFragment: - let typeConditionAST = node.typeCondition - let outputType = typeConditionAST != nil ? typeFromAST(schema: schema, inputTypeAST: typeConditionAST!) : self.type + let outputType: GraphQLType? + if let typeConditionAST = node.typeCondition { + outputType = typeFromAST(schema: schema, inputTypeAST: typeConditionAST) + } else { + outputType = self.type + } typeStack.append(outputType as? GraphQLOutputType) case let node as FragmentDefinition: diff --git a/Sources/GraphQL/Validation/Rules/FieldsOnCorrectTypeRule.swift b/Sources/GraphQL/Validation/Rules/FieldsOnCorrectTypeRule.swift index 0cb46a24..71c2af90 100644 --- a/Sources/GraphQL/Validation/Rules/FieldsOnCorrectTypeRule.swift +++ b/Sources/GraphQL/Validation/Rules/FieldsOnCorrectTypeRule.swift @@ -102,6 +102,7 @@ func getSuggestedTypeNames( // Suggest interface types based on how common they are. let suggestedInterfaceTypes = interfaceUsageCount.keys.sorted { + // Unwraps are safe because keys are from object being sorted. interfaceUsageCount[$1]! - interfaceUsageCount[$0]! >= 0 } diff --git a/Sources/GraphQL/Validation/Validate.swift b/Sources/GraphQL/Validation/Validate.swift index edb0055b..38629264 100644 --- a/Sources/GraphQL/Validation/Validate.swift +++ b/Sources/GraphQL/Validation/Validate.swift @@ -153,105 +153,100 @@ public final class ValidationContext { } public func getFragmentSpreads(node: SelectionSet) -> [FragmentSpread] { - var spreads = fragmentSpreads[node] + if let spreads = fragmentSpreads[node] { + return spreads + } - if spreads == nil { - spreads = [] - var setsToVisit: [SelectionSet] = [node] + var spreads = [FragmentSpread]() + var setsToVisit: [SelectionSet] = [node] - while let set = setsToVisit.popLast() { - for selection in set.selections { - if let selection = selection as? FragmentSpread { - spreads!.append(selection) - } + while let set = setsToVisit.popLast() { + for selection in set.selections { + if let selection = selection as? FragmentSpread { + spreads.append(selection) + } - if let selection = selection as? InlineFragment { - setsToVisit.append(selection.selectionSet) - } + if let selection = selection as? InlineFragment { + setsToVisit.append(selection.selectionSet) + } - if let selection = selection as? Field, let selectionSet = selection.selectionSet { - setsToVisit.append(selectionSet) - } + if let selection = selection as? Field, let selectionSet = selection.selectionSet { + setsToVisit.append(selectionSet) } } - - fragmentSpreads[node] = spreads } - return spreads! + fragmentSpreads[node] = spreads + return spreads } public func getRecursivelyReferencedFragments(operation: OperationDefinition) -> [FragmentDefinition] { - var fragments = recursivelyReferencedFragments[operation] - - if fragments == nil { - fragments = [] - var collectedNames: [String: Bool] = [:] - var nodesToVisit: [SelectionSet] = [operation.selectionSet] - - while let node = nodesToVisit.popLast() { - let spreads = getFragmentSpreads(node: node) - - for spread in spreads { - let fragName = spread.name.value - if collectedNames[fragName] != true { - collectedNames[fragName] = true - if let fragment = getFragment(name: fragName) { - fragments!.append(fragment) - nodesToVisit.append(fragment.selectionSet) - } + if let fragments = recursivelyReferencedFragments[operation] { + return fragments + } + + var fragments = [FragmentDefinition]() + var collectedNames: [String: Bool] = [:] + var nodesToVisit: [SelectionSet] = [operation.selectionSet] + + while let node = nodesToVisit.popLast() { + let spreads = getFragmentSpreads(node: node) + + for spread in spreads { + let fragName = spread.name.value + if collectedNames[fragName] != true { + collectedNames[fragName] = true + if let fragment = getFragment(name: fragName) { + fragments.append(fragment) + nodesToVisit.append(fragment.selectionSet) } } } - - recursivelyReferencedFragments[operation] = fragments } - return fragments! + recursivelyReferencedFragments[operation] = fragments + return fragments } public func getVariableUsages(node: HasSelectionSet) -> [VariableUsage] { - var usages = variableUsages[node] - - if usages == nil { - var newUsages: [VariableUsage] = [] - let typeInfo = TypeInfo(schema: schema) - - visit(root: node.node, visitor: visitWithTypeInfo(typeInfo: typeInfo, visitor: Visitor(enter: { node, _, _, _, _ in - if node is VariableDefinition { - return .skip - } + if let usages = variableUsages[node] { + return usages + } + + var usages = [VariableUsage]() + let typeInfo = TypeInfo(schema: schema) - if let variable = node as? Variable { - newUsages.append(VariableUsage(node: variable, type: typeInfo.inputType)) - } + visit(root: node.node, visitor: visitWithTypeInfo(typeInfo: typeInfo, visitor: Visitor(enter: { node, _, _, _, _ in + if node is VariableDefinition { + return .skip + } - return .continue - }))) + if let variable = node as? Variable { + usages.append(VariableUsage(node: variable, type: typeInfo.inputType)) + } - usages = newUsages - variableUsages[node] = usages - } + return .continue + }))) - return usages! + variableUsages[node] = usages + return usages } public func getRecursiveVariableUsages(operation: OperationDefinition) -> [VariableUsage] { - var usages = recursiveVariableUsages[operation] - - if usages == nil { - usages = getVariableUsages(node: .operation(operation)) - let fragments = getRecursivelyReferencedFragments(operation: operation) - - for fragment in fragments { - let newUsages = getVariableUsages(node: .fragment(fragment)) - usages!.append(contentsOf: newUsages) - } - - recursiveVariableUsages[operation] = usages + if let usages = recursiveVariableUsages[operation] { + return usages } - return usages! + var usages = getVariableUsages(node: .operation(operation)) + let fragments = getRecursivelyReferencedFragments(operation: operation) + + for fragment in fragments { + let newUsages = getVariableUsages(node: .fragment(fragment)) + usages.append(contentsOf: newUsages) + } + + recursiveVariableUsages[operation] = usages + return usages } public var type: GraphQLOutputType? { diff --git a/Tests/GraphQLTests/InputTests/InputTests.swift b/Tests/GraphQLTests/InputTests/InputTests.swift index c9969973..20b0fbaa 100644 --- a/Tests/GraphQLTests/InputTests/InputTests.swift +++ b/Tests/GraphQLTests/InputTests/InputTests.swift @@ -14,7 +14,7 @@ class InputTests : XCTestCase { let field1: String } - let EchoOutputType = try! GraphQLObjectType( + let EchoOutputType = try GraphQLObjectType( name: "Echo", description: "", fields: [ @@ -27,8 +27,8 @@ class InputTests : XCTestCase { } ) - let schema = try! GraphQLSchema( - query: try! GraphQLObjectType( + let schema = try GraphQLSchema( + query: try GraphQLObjectType( name: "Query", fields: [ "echo": GraphQLField( @@ -180,7 +180,7 @@ class InputTests : XCTestCase { let field1: String? } - let EchoOutputType = try! GraphQLObjectType( + let EchoOutputType = try GraphQLObjectType( name: "Echo", description: "", fields: [ @@ -193,8 +193,8 @@ class InputTests : XCTestCase { } ) - let schema = try! GraphQLSchema( - query: try! GraphQLObjectType( + let schema = try GraphQLSchema( + query: try GraphQLObjectType( name: "Query", fields: [ "echo": GraphQLField( @@ -362,7 +362,7 @@ class InputTests : XCTestCase { let field1: String } - let EchoOutputType = try! GraphQLObjectType( + let EchoOutputType = try GraphQLObjectType( name: "Echo", description: "", fields: [ @@ -375,8 +375,8 @@ class InputTests : XCTestCase { } ) - let schema = try! GraphQLSchema( - query: try! GraphQLObjectType( + let schema = try GraphQLSchema( + query: try GraphQLObjectType( name: "Query", fields: [ "echo": GraphQLField( @@ -556,7 +556,7 @@ class InputTests : XCTestCase { let field1: String? } - let EchoOutputType = try! GraphQLObjectType( + let EchoOutputType = try GraphQLObjectType( name: "Echo", description: "", fields: [ @@ -569,8 +569,8 @@ class InputTests : XCTestCase { } ) - let schema = try! GraphQLSchema( - query: try! GraphQLObjectType( + let schema = try GraphQLSchema( + query: try GraphQLObjectType( name: "Query", fields: [ "echo": GraphQLField( @@ -777,7 +777,7 @@ class InputTests : XCTestCase { let input: Echo } - let EchoInputType = try! GraphQLInputObjectType( + let EchoInputType = try GraphQLInputObjectType( name: "EchoInput", fields: [ "field1": InputObjectField( @@ -789,7 +789,7 @@ class InputTests : XCTestCase { ] ) - let EchoOutputType = try! GraphQLObjectType( + let EchoOutputType = try GraphQLObjectType( name: "Echo", description: "", fields: [ @@ -805,8 +805,8 @@ class InputTests : XCTestCase { } ) - let schema = try! GraphQLSchema( - query: try! GraphQLObjectType( + let schema = try GraphQLSchema( + query: try GraphQLObjectType( name: "Query", fields: [ "echo": GraphQLField( @@ -912,7 +912,7 @@ class InputTests : XCTestCase { let input: Echo } - let EchoInputType = try! GraphQLInputObjectType( + let EchoInputType = try GraphQLInputObjectType( name: "EchoInput", fields: [ "field1": InputObjectField( @@ -924,7 +924,7 @@ class InputTests : XCTestCase { ] ) - let EchoOutputType = try! GraphQLObjectType( + let EchoOutputType = try GraphQLObjectType( name: "Echo", description: "", fields: [ @@ -940,8 +940,8 @@ class InputTests : XCTestCase { } ) - let schema = try! GraphQLSchema( - query: try! GraphQLObjectType( + let schema = try GraphQLSchema( + query: try GraphQLObjectType( name: "Query", fields: [ "echo": GraphQLField( @@ -1047,7 +1047,7 @@ class InputTests : XCTestCase { let input: Echo } - let EchoInputType = try! GraphQLInputObjectType( + let EchoInputType = try GraphQLInputObjectType( name: "EchoInput", fields: [ "field1": InputObjectField( @@ -1059,7 +1059,7 @@ class InputTests : XCTestCase { ] ) - let EchoOutputType = try! GraphQLObjectType( + let EchoOutputType = try GraphQLObjectType( name: "Echo", description: "", fields: [ @@ -1075,8 +1075,8 @@ class InputTests : XCTestCase { } ) - let schema = try! GraphQLSchema( - query: try! GraphQLObjectType( + let schema = try GraphQLSchema( + query: try GraphQLObjectType( name: "Query", fields: [ "echo": GraphQLField( @@ -1180,7 +1180,7 @@ class InputTests : XCTestCase { let input: Echo } - let EchoInputType = try! GraphQLInputObjectType( + let EchoInputType = try GraphQLInputObjectType( name: "EchoInput", fields: [ "field1": InputObjectField( @@ -1193,7 +1193,7 @@ class InputTests : XCTestCase { ] ) - let EchoOutputType = try! GraphQLObjectType( + let EchoOutputType = try GraphQLObjectType( name: "Echo", description: "", fields: [ @@ -1209,8 +1209,8 @@ class InputTests : XCTestCase { } ) - let schema = try! GraphQLSchema( - query: try! GraphQLObjectType( + let schema = try GraphQLSchema( + query: try GraphQLObjectType( name: "Query", fields: [ "echo": GraphQLField( diff --git a/Tests/GraphQLTests/LanguageTests/SchemaParserTests.swift b/Tests/GraphQLTests/LanguageTests/SchemaParserTests.swift index fa249e4b..3a31e617 100644 --- a/Tests/GraphQLTests/LanguageTests/SchemaParserTests.swift +++ b/Tests/GraphQLTests/LanguageTests/SchemaParserTests.swift @@ -428,7 +428,8 @@ class SchemaParserTests : XCTestCase { ) let result = try parse(source: source) - XCTAssertEqual(result.definitions[0] as! ObjectTypeDefinition, expected, "\n\(dump(result.definitions[0]))\n\(dump(expected))\n") + let firstDefinition = try XCTUnwrap(result.definitions[0] as? ObjectTypeDefinition) + XCTAssertEqual(firstDefinition, expected, "\n\(dump(firstDefinition))\n\(dump(expected))\n") } func testTypeWitMultilinehDescription() throws { diff --git a/Tests/GraphQLTests/SubscriptionTests/SubscriptionSchema.swift b/Tests/GraphQLTests/SubscriptionTests/SubscriptionSchema.swift index bbe1894d..0b2eef67 100644 --- a/Tests/GraphQLTests/SubscriptionTests/SubscriptionSchema.swift +++ b/Tests/GraphQLTests/SubscriptionTests/SubscriptionSchema.swift @@ -119,8 +119,8 @@ class EmailDb { } /// Returns the default email schema, with standard resolvers. - func defaultSchema() -> GraphQLSchema { - return emailSchemaWithResolvers( + func defaultSchema() throws -> GraphQLSchema { + return try emailSchemaWithResolvers( resolve: {emailAny, _, _, eventLoopGroup, _ throws -> EventLoopFuture in if let email = emailAny as? Email { return eventLoopGroup.next().makeSucceededFuture(EmailEvent( @@ -155,8 +155,8 @@ class EmailDb { } /// Generates an email schema with the specified resolve and subscribe methods -func emailSchemaWithResolvers(resolve: GraphQLFieldResolve? = nil, subscribe: GraphQLFieldResolve? = nil) -> GraphQLSchema { - return try! GraphQLSchema( +func emailSchemaWithResolvers(resolve: GraphQLFieldResolve? = nil, subscribe: GraphQLFieldResolve? = nil) throws -> GraphQLSchema { + return try GraphQLSchema( query: EmailQueryType, subscription: try! GraphQLObjectType( name: "Subscription", diff --git a/Tests/GraphQLTests/SubscriptionTests/SubscriptionTests.swift b/Tests/GraphQLTests/SubscriptionTests/SubscriptionTests.swift index fbb790c4..44db10b9 100644 --- a/Tests/GraphQLTests/SubscriptionTests/SubscriptionTests.swift +++ b/Tests/GraphQLTests/SubscriptionTests/SubscriptionTests.swift @@ -15,7 +15,7 @@ class SubscriptionTests : XCTestCase { /// This test is not present in graphql-js, but just tests basic functionality. func testGraphqlSubscribe() async throws { let db = EmailDb() - let schema = db.defaultSchema() + let schema = try db.defaultSchema() let query = """ subscription ($priority: Int = 0) { importantEmail(priority: $priority) { @@ -78,7 +78,7 @@ class SubscriptionTests : XCTestCase { let db = EmailDb() let schema = try GraphQLSchema( query: EmailQueryType, - subscription: try! GraphQLObjectType( + subscription: GraphQLObjectType( name: "Subscription", fields: [ "importantEmail": GraphQLField( @@ -180,7 +180,7 @@ class SubscriptionTests : XCTestCase { let schema = try GraphQLSchema( query: EmailQueryType, - subscription: try! GraphQLObjectType( + subscription: GraphQLObjectType( name: "Subscription", fields: [ "importantEmail": GraphQLField( @@ -270,7 +270,7 @@ class SubscriptionTests : XCTestCase { /// 'throws an error if subscribe does not return an iterator' func testErrorIfSubscribeIsntIterator() throws { - let schema = emailSchemaWithResolvers( + let schema = try emailSchemaWithResolvers( resolve: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture in return eventLoopGroup.next().makeSucceededFuture(nil) }, @@ -323,21 +323,21 @@ class SubscriptionTests : XCTestCase { } // Throwing an error - verifyError(schema: emailSchemaWithResolvers( + try verifyError(schema: emailSchemaWithResolvers( subscribe: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture in throw GraphQLError(message: "test error") } )) // Resolving to an error - verifyError(schema: emailSchemaWithResolvers( + try verifyError(schema: emailSchemaWithResolvers( subscribe: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture in return eventLoopGroup.next().makeSucceededFuture(GraphQLError(message: "test error")) } )) // Rejecting with an error - verifyError(schema: emailSchemaWithResolvers( + try verifyError(schema: emailSchemaWithResolvers( subscribe: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture in return eventLoopGroup.next().makeFailedFuture(GraphQLError(message: "test error")) } @@ -837,7 +837,7 @@ class SubscriptionTests : XCTestCase { func testErrorDuringSubscription() async throws { let db = EmailDb() - let schema = emailSchemaWithResolvers( + let schema = try emailSchemaWithResolvers( resolve: {emailAny, _, _, eventLoopGroup, _ throws -> EventLoopFuture in guard let email = emailAny as? Email else { throw GraphQLError(message:"Source is not Email type: \(type(of: emailAny))")