From db763a7d77ce853599e7ce599bce813c62fb8093 Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Mon, 22 Jan 2024 10:47:23 -0500 Subject: [PATCH] Updates --- .../GraphQLHttpMiddleware.cs | 38 +++---- .../Middleware/PostTests.cs | 101 ++++++++++-------- 2 files changed, 71 insertions(+), 68 deletions(-) diff --git a/src/Transports.AspNetCore/GraphQLHttpMiddleware.cs b/src/Transports.AspNetCore/GraphQLHttpMiddleware.cs index c2662332..3aceec51 100644 --- a/src/Transports.AspNetCore/GraphQLHttpMiddleware.cs +++ b/src/Transports.AspNetCore/GraphQLHttpMiddleware.cs @@ -1,6 +1,7 @@ #pragma warning disable CA1716 // Identifiers should not match keywords using System.Collections; +using System.Diagnostics; using System.Globalization; using System.Text; using Microsoft.AspNetCore.Authentication; @@ -326,29 +327,22 @@ void ApplyMapToRequests(Dictionary map, IFormCollection form, throw new FileSizeExceededError(); } - try + foreach (var entry in map) { - foreach (var entry in map) + // validate entry key + if (entry.Key == "" || entry.Key == "query" || entry.Key == "operationName" || entry.Key == "variables" || entry.Key == "extensions" || entry.Key == "operations" || entry.Key == "map") + throw new InvalidMapError("Map key cannot be query, operationName, variables, extensions, operations or map."); + // locate file + var file = form.Files[entry.Key] + ?? throw new InvalidMapError("Map key does not refer to an uploaded file."); + // apply file to each target + foreach (var target in entry.Value) { - // validate entry key - if (entry.Key == "" || entry.Key == "query" || entry.Key == "operationName" || entry.Key == "variables" || entry.Key == "extensions" || entry.Key == "operations" || entry.Key == "map") - throw new InvalidMapError("Map key cannot be query, operationName, variables, extensions, operations or map."); - // locate file - var file = form.Files[entry.Key] - ?? throw new InvalidMapError("Map key does not refer to an uploaded file."); - // apply file to each target - foreach (var target in entry.Value) - { - if (target != null) - ApplyFileToRequests(file, target, requests); - } + if (target == null) + throw new InvalidMapError("Map target cannot be null."); + ApplyFileToRequests(file, target, requests); } } - // catch unanticipated exceptions, although this should never happen - catch (Exception ex) when (ex is not ExecutionError) - { - throw new InvalidMapError(ex); - } } // Applies an uploaded file to a specific target property within a list of requests. @@ -436,9 +430,9 @@ static void ApplyFileToRequest(IFormFile file, string target, GraphQLRequest? re prop = location; } - // Verify that the target is valid - if (prop == null || prop.Length == 0) - throw new InvalidMapError("No map path provided."); + // Verify that the target is valid (should not be possible) + Debug.Assert(prop != null); + Debug.Assert(prop!.Length > 0); // Resolve the segment, and set it to the form file diff --git a/tests/Transports.AspNetCore.Tests/Middleware/PostTests.cs b/tests/Transports.AspNetCore.Tests/Middleware/PostTests.cs index e11dda38..75f48ccd 100644 --- a/tests/Transports.AspNetCore.Tests/Middleware/PostTests.cs +++ b/tests/Transports.AspNetCore.Tests/Middleware/PostTests.cs @@ -188,140 +188,149 @@ public async Task FormMultipart_Upload() // successful queries // typical, single file - [InlineData("{\"query\":\"query($arg:FormFile){file(file:$arg){name contentType content}}\",\"variables\":{\"arg\":null}}", "{\"file0\":[\"variables.arg\"]}", true, false, + [InlineData(1, "{\"query\":\"query($arg:FormFile){file(file:$arg){name contentType content}}\",\"variables\":{\"arg\":null}}", "{\"file0\":[\"variables.arg\"]}", true, false, 200, "{\"data\":{\"file\":{\"name\":\"file0\",\"contentType\":\"text/text; charset=utf-8\",\"content\":\"test1\"}}}")] // single file with map specified as 0.variables - [InlineData("{\"query\":\"query($arg:FormFile){file(file:$arg){content}}\",\"variables\":{\"arg\":null}}", "{\"file0\":[\"0.variables.arg\"]}", true, false, + [InlineData(2, "{\"query\":\"query($arg:FormFile){file(file:$arg){content}}\",\"variables\":{\"arg\":null}}", "{\"file0\":[\"0.variables.arg\"]}", true, false, 200, "{\"data\":{\"file\":{\"content\":\"test1\"}}}")] // two files - [InlineData("{\"query\":\"query($arg1:FormFile,$arg2:FormFile){file0:file(file:$arg1){content},file1:file(file:$arg2){content}}\",\"variables\":{\"arg1\":null,\"arg2\":null}}", "{\"file0\":[\"0.variables.arg1\"],\"file1\":[\"0.variables.arg2\"]}", true, true, + [InlineData(3, "{\"query\":\"query($arg1:FormFile,$arg2:FormFile){file0:file(file:$arg1){content},file1:file(file:$arg2){content}}\",\"variables\":{\"arg1\":null,\"arg2\":null}}", "{\"file0\":[\"0.variables.arg1\"],\"file1\":[\"0.variables.arg2\"]}", true, true, 200, "{\"data\":{\"file0\":{\"content\":\"test1\"},\"file1\":{\"content\":\"test2\"}}}")] // batch query of two requests - [InlineData("[{\"query\":\"query($arg:FormFile){file(file:$arg){content}}\",\"variables\":{\"arg\":null}},{\"query\":\"query($arg:FormFile){file(file:$arg){content}}\",\"variables\":{\"arg\":null}}]", "{\"file0\":[\"0.variables.arg\"],\"file1\":[\"1.variables.arg\"]}", true, true, + [InlineData(4, "[{\"query\":\"query($arg:FormFile){file(file:$arg){content}}\",\"variables\":{\"arg\":null}},{\"query\":\"query($arg:FormFile){file(file:$arg){content}}\",\"variables\":{\"arg\":null}}]", "{\"file0\":[\"0.variables.arg\"],\"file1\":[\"1.variables.arg\"]}", true, true, 200, "[{\"data\":{\"file\":{\"content\":\"test1\"}}},{\"data\":{\"file\":{\"content\":\"test2\"}}}]")] // batch query of one request - [InlineData("[{\"query\":\"query($arg:FormFile){file(file:$arg){content}}\",\"variables\":{\"arg\":null}}]", "{\"file0\":[\"variables.arg\"]}", true, false, + [InlineData(5, "[{\"query\":\"query($arg:FormFile){file(file:$arg){content}}\",\"variables\":{\"arg\":null}}]", "{\"file0\":[\"variables.arg\"]}", true, false, 200, "[{\"data\":{\"file\":{\"content\":\"test1\"}}}]")] // referencing a variable's child by index - [InlineData("{\"query\":\"query($arg:[FormFile!]!){file2(files:$arg){content}}\",\"variables\":{\"arg\":[null]}}", "{\"file0\":[\"variables.arg.0\"]}", true, false, + [InlineData(6, "{\"query\":\"query($arg:[FormFile!]!){file2(files:$arg){content}}\",\"variables\":{\"arg\":[null]}}", "{\"file0\":[\"variables.arg.0\"]}", true, false, 200, "{\"data\":{\"file2\":[{\"content\":\"test1\"}]}}")] // referencing a variable's child by property name - [InlineData("{\"query\":\"query($arg:MyFileInput!){file3(arg:$arg){content}}\",\"variables\":{\"arg\":{\"file\":null}}}", "{\"file0\":[\"variables.arg.file\"]}", true, false, + [InlineData(7, "{\"query\":\"query($arg:MyFileInput!){file3(arg:$arg){content}}\",\"variables\":{\"arg\":{\"file\":null}}}", "{\"file0\":[\"variables.arg.file\"]}", true, false, 200, "{\"data\":{\"file3\":{\"content\":\"test1\"}}}")] // referencing a variable's child by index by property name - [InlineData("{\"query\":\"query($arg:[MyFileInput!]!){file4(args:$arg){content}}\",\"variables\":{\"arg\":[{\"file\":null}]}}", "{\"file0\":[\"variables.arg.0.file\"]}", true, false, + [InlineData(8, "{\"query\":\"query($arg:[MyFileInput!]!){file4(args:$arg){content}}\",\"variables\":{\"arg\":[{\"file\":null}]}}", "{\"file0\":[\"variables.arg.0.file\"]}", true, false, 200, "{\"data\":{\"file4\":[{\"content\":\"test1\"}]}}")] // failing queries + // invalid index for request (no requests) + [InlineData(20, "[]", "{\"file0\":[\"variables.arg\"]}", true, false, + 400, "{\"errors\":[{\"message\":\"Invalid map path. No request specified.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // invalid index for request (string not integer) - [InlineData(null, "{\"file0\":[\"abc.variables.arg\"]}", true, false, + [InlineData(21, null, "{\"file0\":[\"abc.variables.arg\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Could not parse the request index.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // invalid index for request - [InlineData(null, "{\"file0\":[\"1.variables.arg\"]}", true, false, + [InlineData(22, null, "{\"file0\":[\"1.variables.arg\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Invalid request index.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // already set variable - [InlineData("{\"query\":\"query($arg:FormFile){file(file:$arg){content}}\",\"variables\":{\"arg\":\"hello\"}}", "{\"file0\":[\"variables.arg\"]}", true, false, + [InlineData(23, "{\"query\":\"query($arg:FormFile){file(file:$arg){content}}\",\"variables\":{\"arg\":\"hello\"}}", "{\"file0\":[\"variables.arg\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Child property \\u0027arg\\u0027 must refer to a null object.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // invalid 'operations' json - [InlineData("{", null, false, false, + [InlineData(24, "{", null, false, false, 400, "{\"errors\":[{\"message\":\"JSON body text could not be parsed. Expected depth to be zero at the end of the JSON payload. There is an open JSON object or array that should be closed. Path: $ | LineNumber: 0 | BytePositionInLine: 1.\",\"extensions\":{\"code\":\"JSON_INVALID\",\"codes\":[\"JSON_INVALID\"]}}]}")] // invalid 'map' json - [InlineData(null, "{", false, false, + [InlineData(25, null, "{", false, false, 400, "{\"errors\":[{\"message\":\"JSON body text could not be parsed. Expected depth to be zero at the end of the JSON payload. There is an open JSON object or array that should be closed. Path: $ | LineNumber: 0 | BytePositionInLine: 1.\",\"extensions\":{\"code\":\"JSON_INVALID\",\"codes\":[\"JSON_INVALID\"]}}]}")] // invalid map path: invalid prefix - [InlineData(null, "{\"file0\":[\"abc\"]}", true, false, + [InlineData(30, null, "{\"file0\":[\"abc\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Map path must start with \\u0027variables.\\u0027 or the index of the request followed by \\u0027.variables.\\u0027.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] - [InlineData(null, "{\"file0\":[\"0.abc\"]}", true, false, + [InlineData(31, null, "{\"file0\":[\"0.abc\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Map path must start with \\u0027variables.\\u0027 or the index of the request followed by \\u0027.variables.\\u0027.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] - [InlineData(null, "{\"file0\":[\"variables\"]}", true, false, + [InlineData(32, null, "{\"file0\":[\"variables\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Map path must start with \\u0027variables.\\u0027 or the index of the request followed by \\u0027.variables.\\u0027.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] - [InlineData(null, "{\"file0\":[\"0.variables\"]}", true, false, + [InlineData(33, null, "{\"file0\":[\"0.variables\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Map path must start with \\u0027variables.\\u0027 or the index of the request followed by \\u0027.variables.\\u0027.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // invalid map path: missing property name - [InlineData(null, "{\"file0\":[\"variables.\"]}", true, false, + [InlineData(34, null, "{\"file0\":[\"variables.\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Empty property name.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] - [InlineData(null, "{\"file0\":[\"0.variables.\"]}", true, false, + [InlineData(35, null, "{\"file0\":[\"0.variables.\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Empty property name.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // invalid map path: child of null specified - [InlineData(null, "{\"file0\":[\"variables.arg.file\"]}", true, false, + [InlineData(36, null, "{\"file0\":[\"variables.arg.file\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Child property \\u0027arg\\u0027 refers to a null object.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // invalid map path: child of string specified - [InlineData("{\"query\":\"query($arg:FormFile){file(file:$arg){name contentType content}}\",\"variables\":{\"arg\":\"hello\"}}", "{\"file0\":[\"variables.arg.file\"]}", true, false, + [InlineData(37, "{\"query\":\"query($arg:FormFile){file(file:$arg){name contentType content}}\",\"variables\":{\"arg\":\"hello\"}}", "{\"file0\":[\"variables.arg.file\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Cannot refer to child property \\u0027file\\u0027 of a string or number.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] + [InlineData(38, "{\"query\":\"query($arg:FormFile){file(file:$arg){name contentType content}}\",\"variables\":{\"arg\":\"hello\"}}", "{\"file0\":[\"variables.arg.file.dummy\"]}", true, false, + 400, "{\"errors\":[{\"message\":\"Invalid map path. Cannot refer to child property \\u0027file\\u0027 of a string or number.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] + // map target is null + [InlineData(39, null, "{\"file0\":[null]}", true, false, + 400, "{\"errors\":[{\"message\":\"Invalid map path. Map target cannot be null.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // invalid map keys - [InlineData(null, "{\"\":[\"0.variables.arg\"]}", false, false, + [InlineData(40, null, "{\"\":[\"0.variables.arg\"]}", false, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Map key cannot be query, operationName, variables, extensions, operations or map.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] - [InlineData(null, "{\"query\":[\"0.variables.arg\"]}", false, false, + [InlineData(41, null, "{\"query\":[\"0.variables.arg\"]}", false, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Map key cannot be query, operationName, variables, extensions, operations or map.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] - [InlineData(null, "{\"variables\":[\"0.variables.arg\"]}", false, false, + [InlineData(42, null, "{\"variables\":[\"0.variables.arg\"]}", false, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Map key cannot be query, operationName, variables, extensions, operations or map.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] - [InlineData(null, "{\"extensions\":[\"0.variables.arg\"]}", false, false, + [InlineData(43, null, "{\"extensions\":[\"0.variables.arg\"]}", false, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Map key cannot be query, operationName, variables, extensions, operations or map.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] - [InlineData(null, "{\"operationName\":[\"0.variables.arg\"]}", false, false, + [InlineData(44, null, "{\"operationName\":[\"0.variables.arg\"]}", false, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Map key cannot be query, operationName, variables, extensions, operations or map.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] - [InlineData(null, "{\"map\":[\"0.variables.arg\"]}", false, false, + [InlineData(45, null, "{\"map\":[\"0.variables.arg\"]}", false, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Map key cannot be query, operationName, variables, extensions, operations or map.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // missing referenced file - [InlineData(null, "{\"file0\":[\"0.variables.arg\"]}", false, false, + [InlineData(50, null, "{\"file0\":[\"0.variables.arg\"]}", false, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Map key does not refer to an uploaded file.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // no variables in request - [InlineData("{}", "{\"file0\":[\"0.variables.arg\"]}", true, false, + [InlineData(51, "{}", "{\"file0\":[\"0.variables.arg\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. No variables defined for this request.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // variables present but not the one referenced - [InlineData(null, "{\"file0\":[\"0.variables.arg2\"]}", true, false, + [InlineData(52, null, "{\"file0\":[\"0.variables.arg2\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Child property \\u0027arg2\\u0027 does not exist.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // invalid variable path - [InlineData(null, "{\"file0\":[\"0.variables.arg.child\"]}", true, false, + [InlineData(53, null, "{\"file0\":[\"0.variables.arg.child\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Child property \\u0027arg\\u0027 refers to a null object.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // file2 tests // missing index in variable path - [InlineData("{\"query\":\"query($arg:[FormFile!]!){file2(files:$arg){content}}\",\"variables\":{\"arg\":[null]}}", "{\"file0\":[\"variables.arg\"]}", true, false, + [InlineData(60, "{\"query\":\"query($arg:[FormFile!]!){file2(files:$arg){content}}\",\"variables\":{\"arg\":[null]}}", "{\"file0\":[\"variables.arg\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Child property \\u0027arg\\u0027 must refer to a null object.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // invalid index in variable path - [InlineData("{\"query\":\"query($arg:[FormFile!]!){file2(files:$arg){content}}\",\"variables\":{\"arg\":[null]}}", "{\"file0\":[\"variables.arg.1\"]}", true, false, + [InlineData(61, "{\"query\":\"query($arg:[FormFile!]!){file2(files:$arg){content}}\",\"variables\":{\"arg\":[null]}}", "{\"file0\":[\"variables.arg.1\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Index \\u00271\\u0027 is out of bounds.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // name instead of index in variable path - [InlineData("{\"query\":\"query($arg:[FormFile!]!){file2(files:$arg){content}}\",\"variables\":{\"arg\":[null]}}", "{\"file0\":[\"variables.arg.abc\"]}", true, false, + [InlineData(62, "{\"query\":\"query($arg:[FormFile!]!){file2(files:$arg){content}}\",\"variables\":{\"arg\":[null]}}", "{\"file0\":[\"variables.arg.abc\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Child index \\u0027abc\\u0027 is not an integer.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // suffix in variable path - [InlineData("{\"query\":\"query($arg:[FormFile!]!){file2(files:$arg){content}}\",\"variables\":{\"arg\":[null]}}", "{\"file0\":[\"variables.arg.0.abc\"]}", true, false, + [InlineData(63, "{\"query\":\"query($arg:[FormFile!]!){file2(files:$arg){content}}\",\"variables\":{\"arg\":[null]}}", "{\"file0\":[\"variables.arg.0.abc\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Child index \\u00270\\u0027 refers to a null object.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // suffix in variable path for string - [InlineData("{\"query\":\"query($arg:[FormFile!]!){file2(files:$arg){content}}\",\"variables\":{\"arg\":[\"test\"]}}", "{\"file0\":[\"variables.arg.0.abc\"]}", true, false, + [InlineData(64, "{\"query\":\"query($arg:[FormFile!]!){file2(files:$arg){content}}\",\"variables\":{\"arg\":[\"test\"]}}", "{\"file0\":[\"variables.arg.0.abc\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Cannot refer to child property \\u0027abc\\u0027 of a string or number.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // already set variable - [InlineData("{\"query\":\"query($arg:[FormFile!]!){file2(files:$arg){content}}\",\"variables\":{\"arg\":[\"test\"]}}", "{\"file0\":[\"variables.arg.0\"]}", true, false, + [InlineData(65, "{\"query\":\"query($arg:[FormFile!]!){file2(files:$arg){content}}\",\"variables\":{\"arg\":[\"test\"]}}", "{\"file0\":[\"variables.arg.0\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Index \\u00270\\u0027 must refer to a null variable.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // file3 tests // missing prop in variable path - [InlineData("{\"query\":\"query($arg:[FormFile!]!){file3(arg:$arg){content}}\",\"variables\":{\"arg\":{\"file\":null}}}", "{\"file0\":[\"variables.arg\"]}", true, false, + [InlineData(70, "{\"query\":\"query($arg:[FormFile!]!){file3(arg:$arg){content}}\",\"variables\":{\"arg\":{\"file\":null}}}", "{\"file0\":[\"variables.arg\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Child property \\u0027arg\\u0027 must refer to a null object.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // invalid prop in variable path - [InlineData("{\"query\":\"query($arg:MyFileInput!){file3(arg:$arg){content}}\",\"variables\":{\"arg\":{\"file\":null}}}", "{\"file0\":[\"variables.arg.1\"]}", true, false, + [InlineData(71, "{\"query\":\"query($arg:MyFileInput!){file3(arg:$arg){content}}\",\"variables\":{\"arg\":{\"file\":null}}}", "{\"file0\":[\"variables.arg.1\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Child property \\u00271\\u0027 does not exist.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // suffix in variable path - [InlineData("{\"query\":\"query($arg:MyFileInput!){file3(arg:$arg){content}}\",\"variables\":{\"arg\":{\"file\":null}}}", "{\"file0\":[\"variables.arg.file.abc\"]}", true, false, + [InlineData(72, "{\"query\":\"query($arg:MyFileInput!){file3(arg:$arg){content}}\",\"variables\":{\"arg\":{\"file\":null}}}", "{\"file0\":[\"variables.arg.file.abc\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Child property \\u0027file\\u0027 refers to a null object.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // suffix in variable path for string - [InlineData("{\"query\":\"query($arg:MyFileInput!){file3(arg:$arg){content}}\",\"variables\":{\"arg\":{\"file\":\"test\"}}}", "{\"file0\":[\"variables.arg.file.abc\"]}", true, false, + [InlineData(73, "{\"query\":\"query($arg:MyFileInput!){file3(arg:$arg){content}}\",\"variables\":{\"arg\":{\"file\":\"test\"}}}", "{\"file0\":[\"variables.arg.file.abc\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Cannot refer to child property \\u0027abc\\u0027 of a string or number.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // already set variable - [InlineData("{\"query\":\"query($arg:MyFileInput!){file3(arg:$arg){content}}\",\"variables\":{\"arg\":{\"file\":\"test\"}}}", "{\"file0\":[\"variables.arg.file\"]}", true, false, + [InlineData(74, "{\"query\":\"query($arg:MyFileInput!){file3(arg:$arg){content}}\",\"variables\":{\"arg\":{\"file\":\"test\"}}}", "{\"file0\":[\"variables.arg.file\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Child property \\u0027file\\u0027 must refer to a null object.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // file4 tests // parent not an integer - [InlineData("{\"query\":\"query($arg:[MyFileInput!]!){file4(args:$arg){content}}\",\"variables\":{\"arg\":[{\"file\":null}]}}", "{\"file0\":[\"variables.arg.test.file\"]}", true, false, + [InlineData(80, "{\"query\":\"query($arg:[MyFileInput!]!){file4(args:$arg){content}}\",\"variables\":{\"arg\":[{\"file\":null}]}}", "{\"file0\":[\"variables.arg.test.file\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Child index \\u0027test\\u0027 is not an integer.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // parent not valid - [InlineData("{\"query\":\"query($arg:[MyFileInput!]!){file4(args:$arg){content}}\",\"variables\":{\"arg\":[{\"file\":null}]}}", "{\"file0\":[\"variables.arg.1.file\"]}", true, false, + [InlineData(81, "{\"query\":\"query($arg:[MyFileInput!]!){file4(args:$arg){content}}\",\"variables\":{\"arg\":[{\"file\":null}]}}", "{\"file0\":[\"variables.arg.1.file\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Index \\u00271\\u0027 is out of bounds.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] // file5 tests // parent not valid - [InlineData("{\"query\":\"query($arg:MyFileInput2!){file5(arg:$arg){content}}\",\"variables\":{\"arg\":{\"files\":[null]}}}", "{\"file0\":[\"variables.arg.dummy.0\"]}", true, false, + [InlineData(90, "{\"query\":\"query($arg:MyFileInput2!){file5(arg:$arg){content}}\",\"variables\":{\"arg\":{\"files\":[null]}}}", "{\"file0\":[\"variables.arg.dummy.0\"]}", true, false, 400, "{\"errors\":[{\"message\":\"Invalid map path. Child property \\u0027dummy\\u0027 does not exist.\",\"extensions\":{\"code\":\"INVALID_MAP\",\"codes\":[\"INVALID_MAP\"]}}]}")] [Theory] - public async Task FormMultipart_Upload_Matrix(string? operations, string? map, bool file0, bool file1, int expectedStatusCode, string expectedResponse) + public async Task FormMultipart_Upload_Matrix(int testIndex, string? operations, string? map, bool file0, bool file1, int expectedStatusCode, string expectedResponse) { + _ = testIndex; operations ??= "{\"query\":\"query($arg:FormFile){file(file:$arg){content}}\",\"variables\":{\"arg\":null}}"; var client = _server.CreateClient(); using var content = new MultipartFormDataContent();