diff --git a/v3/Cargo.lock b/v3/Cargo.lock index 479fd6f1b80..604615741e8 100644 --- a/v3/Cargo.lock +++ b/v3/Cargo.lock @@ -880,6 +880,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "dissimilar" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" + [[package]] name = "dyn-clone" version = "1.0.16" @@ -1011,6 +1017,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "expect-test" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d9eafeadd538e68fb28016364c9732d78e420b9ff8853fa5e4058861e9f8d3" +dependencies = [ + "dissimilar", + "once_cell", +] + [[package]] name = "fastrand" version = "2.0.1" @@ -1669,6 +1685,7 @@ dependencies = [ "bson", "criterion", "diffy", + "expect-test", "graphql-parser", "http", "human_bytes", diff --git a/v3/README.md b/v3/README.md index 638b66a53d8..8a4234b693c 100644 --- a/v3/README.md +++ b/v3/README.md @@ -14,7 +14,7 @@ For local development, we use the reference agent implementation that is a part To start the reference agent only, you can do: ```sh -docker-compose up reference_agent +docker compose up reference_agent ``` and point the host name `reference_agent` to localhost in your `/etc/hosts` file. diff --git a/v3/lang-graphql/Cargo.toml b/v3/lang-graphql/Cargo.toml index e8665e74d90..4152405dfd4 100644 --- a/v3/lang-graphql/Cargo.toml +++ b/v3/lang-graphql/Cargo.toml @@ -32,6 +32,7 @@ bson = "2.6.0" bincode = "1.3.3" human_bytes = "0.4.1" diffy = "0.3.0" +expect-test = "1.4" [[bench]] name = "lexer" diff --git a/v3/lang-graphql/benches/parser.rs b/v3/lang-graphql/benches/parser.rs index 9d4c0c294fc..e885e483109 100644 --- a/v3/lang-graphql/benches/parser.rs +++ b/v3/lang-graphql/benches/parser.rs @@ -37,7 +37,7 @@ pub fn bench_parser(c: &mut Criterion) { group.bench_with_input( BenchmarkId::new("hasura", query_name), &query, - |b, query| b.iter(|| Parser::new(query).parse_executable_document()), + |b, query| b.iter(|| Parser::new(query).parse_executable_document().unwrap()), ); } group.finish(); diff --git a/v3/lang-graphql/src/ast/executable.rs b/v3/lang-graphql/src/ast/executable.rs index 378e98b47dc..7e266c31d99 100644 --- a/v3/lang-graphql/src/ast/executable.rs +++ b/v3/lang-graphql/src/ast/executable.rs @@ -21,6 +21,8 @@ pub enum ExecutableDefinition { /// The operations of a GraphQL document. /// /// There is either one anonymous operation or many named operations. +/// FIXME: I think we should use this? Then move the +/// lang-graphql/tests/query_testdata/ok/0001_empty test from 'ok' to 'err // #[derive(Debug, Clone)] // pub enum DocumentOperations { // /// The document contains a single anonymous operation. diff --git a/v3/lang-graphql/src/lexer.rs b/v3/lang-graphql/src/lexer.rs index 8f3684d7c36..8b2eed59d8a 100644 --- a/v3/lang-graphql/src/lexer.rs +++ b/v3/lang-graphql/src/lexer.rs @@ -1,3 +1,5 @@ +/// Lexer for both executable documents (i.e. graphql queries) and schema documents (SDL), which +/// share a common syntax use std::fmt::Display; use std::str::{from_utf8_unchecked, FromStr}; use std::{char, iter::Iterator}; diff --git a/v3/lang-graphql/src/lexer/string.rs b/v3/lang-graphql/src/lexer/string.rs index 663dd8554db..697f266b2c3 100644 --- a/v3/lang-graphql/src/lexer/string.rs +++ b/v3/lang-graphql/src/lexer/string.rs @@ -29,6 +29,13 @@ pub enum Error { /// when e.g. `"\l"` is parsed. #[error("unknown escape sequence in string: {0:?}")] UnknownEscapeSequence(String), + + /// An invalid unicode escape sequence in a string literal was found, and + /// an error message is provided. + /// + /// This began with `"\u"` being parsed and then something going wrong. + #[error("invalid unicode escape sequence in string. {0:?}")] + InvalidUnicodeEscapeSequence(String), } pub struct Consumed { @@ -232,10 +239,44 @@ fn parse_single_line_string(bytes: &[u8]) -> Result<(String, Consumed, usize), ( b'n' => ('\u{000A}', 1), b'r' => ('\u{000D}', 1), b't' => ('\u{0009}', 1), - // TODO, parse unicode escape sequences - // b'u' => { - // todo!() - // } + // unicode escape sequence: + b'u' => { + if i + 5 >= bytes.len() { + return Err((Error::Unterminated, Consumed::no_line_break(chars))); + } + + // Collect the next 4 characters as hex digits + let hex_str = &bytes[i + 2..i + 6]; + let hex = std::str::from_utf8(hex_str).map_err(|_| { + ( + Error::InvalidUnicodeEscapeSequence( + "invalid format".to_string(), + ), + Consumed::no_line_break(chars), + ) + })?; + + let code_point = u32::from_str_radix(hex, 16).map_err(|_| { + ( + Error::InvalidUnicodeEscapeSequence( + "invalid hex digits".to_string(), + ), + Consumed::no_line_break(chars), + ) + })?; + + let c = std::char::from_u32(code_point).ok_or_else(|| { + ( + Error::InvalidUnicodeEscapeSequence(format!( + "0x{:X} is not a valid code point", + code_point + )), + Consumed::no_line_break(chars), + ) + })?; + + (c, 5) // 5 bytes consumed: u, and the 4 hex digits + } b => { return Err(( Error::UnknownEscapeSequence(format!("\\{b}")), diff --git a/v3/lang-graphql/src/parser.rs b/v3/lang-graphql/src/parser.rs index 672b29a0efa..dab4735eee5 100644 --- a/v3/lang-graphql/src/parser.rs +++ b/v3/lang-graphql/src/parser.rs @@ -17,32 +17,35 @@ pub struct Parser<'a> { } #[derive(Error, Debug, PartialEq, Clone)] -pub struct Error { - expected_tokens: &'static [ExpectedToken], - found: TokenFound, +pub enum Error { + TokenError { + expected_tokens: &'static [ExpectedToken], + found: TokenFound, + }, + /// For other parse errors, just supply an error message. + OtherError(&'static str), } impl Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let expected_tokens = self - .expected_tokens - .iter() - .fold(String::new(), |acc, expected_token| { - acc + &expected_token.to_string() + ", " - }); - let found = &self.found; - write!( - f, - "expected one of {expected_tokens}, but encountered: {found}" - ) - } -} - -impl Error { - pub fn new(expected_tokens: &'static [ExpectedToken], found: TokenFound) -> Self { - Error { - expected_tokens, - found, + match self { + Error::TokenError { + expected_tokens, + found, + } => { + let expected_tokens_str = expected_tokens + .iter() + .fold(String::new(), |acc, expected_token| { + acc + &expected_token.to_string() + ", " + }); + write!( + f, + "expected one of {expected_tokens_str}, but encountered: {found}" + ) + } + Error::OtherError(msg) => { + write!(f, "{}", msg) + } } } } @@ -256,7 +259,10 @@ impl<'a> Parser<'a> { fn eof(&self, expected_tokens: &'static [ExpectedToken]) -> Result { Err(Positioned::new( &self.lexer.get_position(), - Error::new(expected_tokens, TokenFound::EndOfFile), + Error::TokenError { + expected_tokens, + found: TokenFound::EndOfFile, + }, )) } @@ -266,18 +272,27 @@ impl<'a> Parser<'a> { ) -> Result { Err(Positioned::new( &error.position, - Error::new(expected_tokens, TokenFound::LexerError(error.item.clone())), + Error::TokenError { + expected_tokens, + found: TokenFound::LexerError(error.item.clone()), + }, )) } + fn other_error(error_msg: &'static str, start: SourcePosition) -> Result { + Err(Positioned::new(&start, Error::OtherError(error_msg))) + } fn unexpected_token( - expected: &'static [ExpectedToken], + expected_tokens: &'static [ExpectedToken], found: lexer::Token, location: &SourcePosition, ) -> Result { Err(Positioned::new( location, - Error::new(expected, TokenFound::Token(found)), + Error::TokenError { + expected_tokens, + found: TokenFound::Token(found), + }, )) } @@ -352,14 +367,48 @@ impl<'a> Parser<'a> { Ok(items) } - /// Parse delimited items into a `List` - /// * - fn parse_delimited_list( + /// Parse one or more delimited items into a `List` + /// + + /// + /// This corresponds to occurrences of symbol plus the "LIST" subscript in the grammar given in + /// the spec. See: + /// https://spec.graphql.org/October2021/#sec-Grammar-Notation.Optionality-and-Lists + /// + /// TODO Ideally return NonEmpty here + fn parse_nonempty_delimited_list( &mut self, start_token: lexer::Punctuation, end_token: lexer::Punctuation, parse: F, ) -> Result>> + where + F: Fn(&mut Self) -> Result, + { + self.parse_delimited_list_helper(start_token, end_token, parse, true) + } + + /// Parse zero or more delimited items into a `List` + /// * + fn parse_possibly_empty_delimited_list( + &mut self, + start_token: lexer::Punctuation, + end_token: lexer::Punctuation, + parse: F, + ) -> Result>> + where + F: Fn(&mut Self) -> Result, + { + self.parse_delimited_list_helper(start_token, end_token, parse, false) + } + // NOTE: we'd like this to be private to this scope, but functionality is used in child + // modules. + fn parse_delimited_list_helper( + &mut self, + start_token: lexer::Punctuation, + end_token: lexer::Punctuation, + parse: F, + must_be_nonempty: bool, + ) -> Result>> where F: Fn(&mut Self) -> Result, { @@ -370,12 +419,17 @@ impl<'a> Parser<'a> { items.push(parse(self)?); } let end = self.parse_punctuation(end_token)?; + if must_be_nonempty && items.is_empty() { + return Self::other_error("At least one item must be specified", end.start); + } Ok(Spanning::start_end(start.start, end.end, items)) } - /// Parse optional delimited items into a `List` - /// ( * )? - fn parse_optional_delimited_list( + /// Parse an optional delimited list of one or more items into a `List` + /// ( + )? + /// + /// TODO Ideally return NonEmpty here + fn parse_optional_nonempty_delimited_list( &mut self, start_token: lexer::Punctuation, end_token: lexer::Punctuation, @@ -385,10 +439,11 @@ impl<'a> Parser<'a> { F: Fn(&mut Self) -> Result, { if self.is_next_token(&lexer::Token::Punctuation(start_token.clone())) { - Ok(Some(self.parse_delimited_list( + Ok(Some(self.parse_delimited_list_helper( start_token, end_token, parse, + true, )?)) } else { Ok(None) diff --git a/v3/lang-graphql/src/parser/executable.rs b/v3/lang-graphql/src/parser/executable.rs index b4ac83a235e..a5da3ab47a0 100644 --- a/v3/lang-graphql/src/parser/executable.rs +++ b/v3/lang-graphql/src/parser/executable.rs @@ -36,10 +36,10 @@ impl<'a> Parser<'a> { } _ => Err(Positioned::new( &token.start, - super::Error::new( - EXPECTED_TOKENS, - super::TokenFound::Token(token.item.clone()), - ), + super::Error::TokenError { + expected_tokens: EXPECTED_TOKENS, + found: super::TokenFound::Token(token.item.clone()), + }, )), }, } @@ -88,7 +88,7 @@ impl<'a> Parser<'a> { pub fn parse_variable_definitions( &mut self, ) -> super::Result>>>> { - self.parse_optional_delimited_list( + self.parse_optional_nonempty_delimited_list( lexer::Punctuation::ParenL, lexer::Punctuation::ParenR, |s| s.parse_variable_definition(), @@ -129,19 +129,19 @@ impl<'a> Parser<'a> { } else { Err(Positioned::new( &token.start, - super::Error::new( - EXPECTED_TOKENS, - super::TokenFound::Token(lexer::Token::Name(token.item)), - ), + super::Error::TokenError { + expected_tokens: EXPECTED_TOKENS, + found: super::TokenFound::Token(lexer::Token::Name(token.item)), + }, )) } } _ => Err(Positioned::new( &token.start, - super::Error::new( - EXPECTED_TOKENS, - super::TokenFound::Token(token.item.clone()), - ), + super::Error::TokenError { + expected_tokens: EXPECTED_TOKENS, + found: super::TokenFound::Token(token.item.clone()), + }, )), }, } @@ -162,10 +162,10 @@ impl<'a> Parser<'a> { lexer::Token::Punctuation(lexer::Punctuation::BraceL) => Ok(None), _ => Err(Positioned::new( &token.start, - super::Error::new( - EXPECTED_TOKENS, - super::TokenFound::Token(token.item.clone()), - ), + super::Error::TokenError { + expected_tokens: EXPECTED_TOKENS, + found: super::TokenFound::Token(token.item.clone()), + }, )), }, }?; @@ -208,6 +208,7 @@ impl<'a> Parser<'a> { )) } } + // https://spec.graphql.org/October2021/#sec-Executable-Definitions pub fn parse_executable_definition(&mut self) -> super::Result> { static EXPECTED_TOKENS: &[super::ExpectedToken] = &[ super::ExpectedToken::Keyword(super::Keyword::Query), @@ -232,14 +233,15 @@ impl<'a> Parser<'a> { } _ => Err(Positioned::new( &token.start, - super::Error::new( - EXPECTED_TOKENS, - super::TokenFound::Token(token.item.clone()), - ), + super::Error::TokenError { + expected_tokens: EXPECTED_TOKENS, + found: super::TokenFound::Token(token.item.clone()), + }, )), }, } } + /// The top-level parser for a graphql request pub fn parse_executable_document(&mut self) -> super::Result { let mut items = vec![]; while self.peek().is_some() { diff --git a/v3/lang-graphql/src/parser/fragment.rs b/v3/lang-graphql/src/parser/fragment.rs index f91b3aa4a2c..adb8744e79f 100644 --- a/v3/lang-graphql/src/parser/fragment.rs +++ b/v3/lang-graphql/src/parser/fragment.rs @@ -2,9 +2,18 @@ use super::Parser; use crate::ast::{executable::FragmentDefinition, spanning::Spanning}; impl<'a> Parser<'a> { + // https://spec.graphql.org/October2021/#sec-Language.Fragments pub fn parse_fragment(&mut self) -> super::Result> { let start_position = self.parse_keyword(&super::Keyword::Fragment)?.start; let name = self.parse_name()?; + // It seems like this is in the spec to make parsing easier, or possibly unambiguous in the + // presence of directives? + if name.item.as_str() == "on" { + return Self::other_error( + "A fragment may not be named \"on\". Maybe you forgot the name?", + name.start, + ); + } let type_condition = self.parse_type_condition()?; let directives = self.parse_directives()?; let selection_set = self.parse_selection_set()?; diff --git a/v3/lang-graphql/src/parser/schema.rs b/v3/lang-graphql/src/parser/schema.rs index 0afc2a3dc11..66bf5333214 100644 --- a/v3/lang-graphql/src/parser/schema.rs +++ b/v3/lang-graphql/src/parser/schema.rs @@ -54,7 +54,7 @@ impl<'a> Parser<'a> { let start_position = get_start_position(&description, &self.parse_keyword(&super::Keyword::Schema)?); let directives = self.parse_const_directives()?; - let operation_types = self.parse_delimited_list( + let operation_types = self.parse_nonempty_delimited_list( lexer::Punctuation::BraceL, lexer::Punctuation::BraceR, |s| { @@ -103,7 +103,7 @@ impl<'a> Parser<'a> { fn parse_const_arguments( &mut self, ) -> super::Result>>>> { - self.parse_optional_delimited_list( + self.parse_optional_nonempty_delimited_list( lexer::Punctuation::ParenL, lexer::Punctuation::ParenR, |s| s.parse_input_value_definition(), @@ -163,7 +163,7 @@ impl<'a> Parser<'a> { fn parse_fields_definition( &mut self, ) -> super::Result>>> { - self.parse_delimited_list( + self.parse_nonempty_delimited_list( lexer::Punctuation::BraceL, lexer::Punctuation::BraceR, |s| s.parse_field_definition(), @@ -205,10 +205,10 @@ impl<'a> Parser<'a> { } _ => Err(Positioned::new( &token.start, - super::Error::new( - EXPECTED_TOKENS, - super::TokenFound::Token(token.item.clone()), - ), + super::Error::TokenError{ + expected_tokens: EXPECTED_TOKENS, + found: super::TokenFound::Token(token.item.clone()), + }, )), }, } @@ -302,10 +302,10 @@ impl<'a> Parser<'a> { } _ => Err(Positioned::new( &token.start, - super::Error::new( - EXPECTED_TOKENS, - super::TokenFound::Token(token.item.clone()), - ), + super::Error::TokenError { + expected_tokens: EXPECTED_TOKENS, + found: super::TokenFound::Token(token.item.clone()), + }, )), }, } @@ -347,7 +347,7 @@ impl<'a> Parser<'a> { get_start_position(&description, &self.parse_keyword(&super::Keyword::Enum)?); let name = self.parse_name()?; let directives = self.parse_const_directives()?; - let values = self.parse_delimited_list( + let values = self.parse_nonempty_delimited_list( lexer::Punctuation::BraceL, lexer::Punctuation::BraceR, |s| { @@ -386,7 +386,7 @@ impl<'a> Parser<'a> { get_start_position(&description, &self.parse_keyword(&super::Keyword::Input)?); let name = self.parse_name()?; let directives = self.parse_const_directives()?; - let fields = self.parse_delimited_list( + let fields = self.parse_nonempty_delimited_list( lexer::Punctuation::BraceL, lexer::Punctuation::BraceR, |s| s.parse_input_value_definition(), @@ -447,18 +447,18 @@ impl<'a> Parser<'a> { } _ => Err(Positioned::new( &token.start, - super::Error::new( - EXPECTED_TOKENS, - super::TokenFound::Token(token.item.clone()), - ), + super::Error::TokenError { + expected_tokens: EXPECTED_TOKENS, + found: super::TokenFound::Token(token.item.clone()), + }, )), }, _ => Err(Positioned::new( &token.start, - super::Error::new( - EXPECTED_TOKENS, - super::TokenFound::Token(token.item.clone()), - ), + super::Error::TokenError { + expected_tokens: EXPECTED_TOKENS, + found: super::TokenFound::Token(token.item.clone()), + }, )), }, } diff --git a/v3/lang-graphql/src/parser/selection_set.rs b/v3/lang-graphql/src/parser/selection_set.rs index c9c344352d7..8de7ed20ea9 100644 --- a/v3/lang-graphql/src/parser/selection_set.rs +++ b/v3/lang-graphql/src/parser/selection_set.rs @@ -38,7 +38,7 @@ impl<'a> Parser<'a> { } pub fn parse_selection_set(&mut self) -> super::Result> { - self.parse_delimited_list( + self.parse_nonempty_delimited_list( lexer::Punctuation::BraceL, lexer::Punctuation::BraceR, |s| s.parse_selection(), @@ -122,7 +122,7 @@ impl<'a> Parser<'a> { } pub fn parse_arguments(&mut self) -> super::Result>>> { - self.parse_optional_delimited_list( + self.parse_optional_nonempty_delimited_list( lexer::Punctuation::ParenL, lexer::Punctuation::ParenR, |s| s.parse_key_value(|r| r.parse_value()), diff --git a/v3/lang-graphql/src/parser/value.rs b/v3/lang-graphql/src/parser/value.rs index 489e2f492c0..3b3905019b8 100644 --- a/v3/lang-graphql/src/parser/value.rs +++ b/v3/lang-graphql/src/parser/value.rs @@ -104,7 +104,7 @@ impl<'a> Parser<'a> { ]; match self.peek_fail(EXPECTED_TOKENS)?.item { lexer::Token::Punctuation(lexer::Punctuation::BracketL) => { - let list = self.parse_delimited_list( + let list = self.parse_possibly_empty_delimited_list( lexer::Punctuation::BracketL, lexer::Punctuation::BracketR, |s| s.parse_const_value(), @@ -112,7 +112,7 @@ impl<'a> Parser<'a> { Ok(list.map(ConstValue::List)) } lexer::Token::Punctuation(lexer::Punctuation::BraceL) => { - let list = self.parse_delimited_list( + let list = self.parse_possibly_empty_delimited_list( lexer::Punctuation::BraceL, lexer::Punctuation::BraceR, |s| s.parse_key_value(|r| r.parse_const_value()), @@ -149,7 +149,7 @@ impl<'a> Parser<'a> { } // [ (,)* ] lexer::Token::Punctuation(lexer::Punctuation::BracketL) => { - let list = self.parse_delimited_list( + let list = self.parse_possibly_empty_delimited_list( lexer::Punctuation::BracketL, lexer::Punctuation::BracketR, |s| s.parse_value(), @@ -158,7 +158,7 @@ impl<'a> Parser<'a> { } // { (: ,)* } lexer::Token::Punctuation(lexer::Punctuation::BraceL) => { - let list = self.parse_delimited_list( + let list = self.parse_possibly_empty_delimited_list( lexer::Punctuation::BraceL, lexer::Punctuation::BraceR, |s| s.parse_key_value(|r| r.parse_value()), diff --git a/v3/lang-graphql/tests/LICENSE-MIT b/v3/lang-graphql/tests/LICENSE-MIT new file mode 100644 index 00000000000..b465a5d614f --- /dev/null +++ b/v3/lang-graphql/tests/LICENSE-MIT @@ -0,0 +1,7 @@ +Copyright 2021 Apollo Graph, Inc. + +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. diff --git a/v3/lang-graphql/tests/README.md b/v3/lang-graphql/tests/README.md new file mode 100644 index 00000000000..12ed07fdf08 --- /dev/null +++ b/v3/lang-graphql/tests/README.md @@ -0,0 +1,19 @@ +- `testdata` contains snapshot/golden test inputs and expectations for SDL parsing +- `query_testdata` and `schema_data` were later added, but for + executable documents and SDL respectively. Theses cases were copied from the + apollo-rs project at 721e0753 and the license at `lang-graphql/tests/LICENSE-MIT` + applies to these. Cases added subsequently are licensed under this project's + top-level license. +- some cases from the apollo lexer tests are copied with a 9xxx prefix +- `schema_data` cases are currently unused (TODO if SDL parsing is important) + +A few full `parse()` cases were also added from +[graphql-js tests](https://github.com/graphql/graphql-js/blob/main/src/language/__tests__/parser-test.ts) +although they were not numerous or very interesting. They are added starting at `ok/1111_*` + +Some `ok` cases that are only valid for the 2021 spec were renamed to `*.2021` and ignored. + +# TODO + +- the `ok` case output mostly has not been audited +- We might port the old `testdata` cases to the framework taken from apollo since it is nicer. diff --git a/v3/lang-graphql/tests/parser_test.rs b/v3/lang-graphql/tests/parser_test.rs index 48bb5af67b1..da1925da005 100644 --- a/v3/lang-graphql/tests/parser_test.rs +++ b/v3/lang-graphql/tests/parser_test.rs @@ -1,8 +1,13 @@ +use indexmap::IndexMap; +/// Test both schema and query parsing use lang_graphql::parser; -use std::env; -use std::fs; use std::io; -use std::path::PathBuf; +use std::{ + env, fs, + path::{Path, PathBuf}, +}; + +use expect_test::expect_file; #[cfg(test)] fn test_parser_for_schema(schema_path: PathBuf) -> Result<(), io::Error> { @@ -44,8 +49,10 @@ fn test_parser_for_schema(schema_path: PathBuf) -> Result<(), io::Error> { Ok(()) } +/// Test SDL parsing. For each .graphql file with an accompanying .ast.txt file, make sure +/// parse_schema_document() of the former results in the latter. #[test] -fn test_parser() -> Result<(), io::Error> { +fn test_schema_parser() -> Result<(), io::Error> { let mut testdata = PathBuf::from(env!("CARGO_MANIFEST_DIR")); testdata.push("tests"); testdata.push("testdata"); @@ -60,3 +67,141 @@ fn test_parser() -> Result<(), io::Error> { } Ok(()) } + +#[test] +fn query_parser_wellformed_input_tests() { + dir_tests(&test_data_dir(), &["ok"], "txt", |text, path| { + let cst = parser::Parser::new(text).parse_executable_document(); + assert_is_ok(&cst, path); + format!("{cst:#?}") + }); +} + +#[test] +fn query_parser_malformed_input_tests() { + dir_tests(&test_data_dir(), &["err"], "txt", |text, path| { + let cst = parser::Parser::new(text).parse_executable_document(); + assert_is_err(&cst, path); + format!("{cst:#?}") + }); +} + +// ----------------------------------------------------------------------------------------------- +// Code below was copied or adapted from the apollo-rs project at 721e0753 and the license at +// `lang-graphql/tests/LICENSE-MIT` applies. + +/// Compares input code taken from a `.graphql` file in test_fixtures and its +/// expected output in the corresponding `.txt` file. +/// +/// The test fails if the ouptut differs. +/// +/// If a matching file does not exist, it will be created, filled with output, +/// but fail the test. +fn dir_tests(test_data_dir: &Path, paths: &[&str], outfile_extension: &str, f: F) +where + F: Fn(&str, &Path) -> String, +{ + for (path, input_code) in collect_graphql_files(test_data_dir, paths) { + let actual = f(&input_code, &path); + let path = path.with_extension(outfile_extension); + // TODO: we really want formatted output here, but: + // https://github.com/rust-analyzer/expect-test/issues/45 + expect_file![path].assert_eq(&actual) + } +} + +/// Collects all `.graphql` files from `dir` subdirectories defined by `paths`. +fn collect_graphql_files(root_dir: &Path, paths: &[&str]) -> Vec<(PathBuf, String)> { + paths + .iter() + .flat_map(|path| { + let path = root_dir.to_owned().join(path); + graphql_files_in_dir(&path).into_iter() + }) + .map(|path| { + let text = fs::read_to_string(&path) + .unwrap_or_else(|_| panic!("File at {path:?} should be valid")); + (path, text) + }) + .collect() +} + +/// Collects paths to all `.graphql` files from `dir` in a sorted `Vec`. +fn graphql_files_in_dir(dir: &Path) -> Vec { + let mut paths = fs::read_dir(dir) + .unwrap() + .map(|file| { + let file = file?; + let path = file.path(); + if path.extension().unwrap_or_default() == "graphql" { + Ok(Some(path)) + } else { + Ok(None) + } + }) + // Get rid of the `None`s + .filter_map(|result: std::io::Result<_>| result.transpose()) + .collect::, _>>() + .unwrap(); + + paths.sort(); + + // Check for duplicate numbers. + let mut seen = IndexMap::new(); + let next_number = paths.len() + 1; + for path in &paths { + let file_name = path.file_name().unwrap().to_string_lossy(); + let (number, name): (usize, _) = match file_name.split_once('_') { + Some((number, name)) => match number.parse() { + Ok(number) => (number, name), + Err(err) => { + panic!("Invalid test file name: {path:?} does not start with a number ({err})") + } + }, + None => panic!("Invalid test file name: {path:?} does not start with a number"), + }; + + if let Some(existing) = seen.get(&number) { + let suggest = dir.join(format!("{next_number:03}_{name}")); + panic!("Conflicting test file: {path:?} has the same number as {existing:?}. Suggested name: {suggest:?}"); + } + + seen.insert(number, path); + } + + paths +} + +/// PathBuf of test cases directory. +fn test_data_dir() -> PathBuf { + project_root().join("lang-graphql/tests/query_testdata") +} + +/// project root. +fn project_root() -> PathBuf { + Path::new( + &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()), + ) + .ancestors() + .nth(1) + .unwrap() + .to_path_buf() +} + +// Additional sanity checks to distinguish our error and success expectations: +fn assert_is_err(actual: &parser::Result, path: &Path) { + if actual.is_ok() { + println!("erroneously successful parse: {:?}", actual); + panic!( + "There should be errors in the file since this is an error case, but saw none in {:?}", + path.display() + ); + } +} + +fn assert_is_ok(actual: &parser::Result, path: &Path) { + if actual.is_err() { + println!("error: {:?}", actual); + panic!("There should be no errors in the file {:?}", path.display(),); + } +} diff --git a/v3/lang-graphql/tests/query_testdata/err/0007_fragment_definition_with_invalid_fragment_name.graphql b/v3/lang-graphql/tests/query_testdata/err/0007_fragment_definition_with_invalid_fragment_name.graphql new file mode 100644 index 00000000000..00b07255c84 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0007_fragment_definition_with_invalid_fragment_name.graphql @@ -0,0 +1,3 @@ +fragment on User @example { + id +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0007_fragment_definition_with_invalid_fragment_name.txt b/v3/lang-graphql/tests/query_testdata/err/0007_fragment_definition_with_invalid_fragment_name.txt new file mode 100644 index 00000000000..4978a59cb31 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0007_fragment_definition_with_invalid_fragment_name.txt @@ -0,0 +1,11 @@ +Err( + Positioned { + item: OtherError( + "A fragment may not be named \"on\". Maybe you forgot the name?", + ), + position: SourcePosition { + line: 1, + col: 10, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0008_fragment_definition_with_invalid_type_condition.graphql b/v3/lang-graphql/tests/query_testdata/err/0008_fragment_definition_with_invalid_type_condition.graphql new file mode 100644 index 00000000000..aaf54fe4896 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0008_fragment_definition_with_invalid_type_condition.graphql @@ -0,0 +1,3 @@ +fragment friendFields User @example { + id +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0008_fragment_definition_with_invalid_type_condition.txt b/v3/lang-graphql/tests/query_testdata/err/0008_fragment_definition_with_invalid_type_condition.txt new file mode 100644 index 00000000000..54a9c82b8bd --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0008_fragment_definition_with_invalid_type_condition.txt @@ -0,0 +1,22 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Keyword( + On, + ), + ], + found: Token( + Name( + Name( + "User", + ), + ), + ), + }, + position: SourcePosition { + line: 1, + col: 23, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0009_fragment_definition_with_invalid_selection_set.graphql b/v3/lang-graphql/tests/query_testdata/err/0009_fragment_definition_with_invalid_selection_set.graphql new file mode 100644 index 00000000000..4d1822c23a5 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0009_fragment_definition_with_invalid_selection_set.graphql @@ -0,0 +1 @@ +fragment friendFields on User \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0009_fragment_definition_with_invalid_selection_set.txt b/v3/lang-graphql/tests/query_testdata/err/0009_fragment_definition_with_invalid_selection_set.txt new file mode 100644 index 00000000000..34f9b71f760 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0009_fragment_definition_with_invalid_selection_set.txt @@ -0,0 +1,16 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Punctuation( + BraceL, + ), + ], + found: EndOfFile, + }, + position: SourcePosition { + line: 1, + col: 30, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0024_document_with_incorrect_definition.graphql b/v3/lang-graphql/tests/query_testdata/err/0024_document_with_incorrect_definition.graphql new file mode 100644 index 00000000000..7045c520820 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0024_document_with_incorrect_definition.graphql @@ -0,0 +1 @@ +awsas8d2934213hkj0987 \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0024_document_with_incorrect_definition.txt b/v3/lang-graphql/tests/query_testdata/err/0024_document_with_incorrect_definition.txt new file mode 100644 index 00000000000..b06fe63741d --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0024_document_with_incorrect_definition.txt @@ -0,0 +1,28 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Keyword( + Query, + ), + Keyword( + Mutation, + ), + Keyword( + Subscription, + ), + ], + found: Token( + Name( + Name( + "awsas8d2934213hkj0987", + ), + ), + ), + }, + position: SourcePosition { + line: 1, + col: 1, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0025_document_with_incorrect_definition_and_selection_set.graphql b/v3/lang-graphql/tests/query_testdata/err/0025_document_with_incorrect_definition_and_selection_set.graphql new file mode 100644 index 00000000000..082b51127a6 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0025_document_with_incorrect_definition_and_selection_set.graphql @@ -0,0 +1,6 @@ +uasdf21230jkdw + +{ + pet + faveSnack +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0025_document_with_incorrect_definition_and_selection_set.txt b/v3/lang-graphql/tests/query_testdata/err/0025_document_with_incorrect_definition_and_selection_set.txt new file mode 100644 index 00000000000..6fbe28284be --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0025_document_with_incorrect_definition_and_selection_set.txt @@ -0,0 +1,28 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Keyword( + Query, + ), + Keyword( + Mutation, + ), + Keyword( + Subscription, + ), + ], + found: Token( + Name( + Name( + "uasdf21230jkdw", + ), + ), + ), + }, + position: SourcePosition { + line: 1, + col: 1, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0027_invalid_type_system_extension.graphql b/v3/lang-graphql/tests/query_testdata/err/0027_invalid_type_system_extension.graphql new file mode 100644 index 00000000000..d54d5e15cdb --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0027_invalid_type_system_extension.graphql @@ -0,0 +1 @@ +extend Cat \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0027_invalid_type_system_extension.txt b/v3/lang-graphql/tests/query_testdata/err/0027_invalid_type_system_extension.txt new file mode 100644 index 00000000000..4463d68d5a2 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0027_invalid_type_system_extension.txt @@ -0,0 +1,28 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Keyword( + Query, + ), + Keyword( + Mutation, + ), + Keyword( + Subscription, + ), + ], + found: Token( + Name( + Name( + "extend", + ), + ), + ), + }, + position: SourcePosition { + line: 1, + col: 1, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0029_operation_definition_with_empty_selection_set.graphql b/v3/lang-graphql/tests/query_testdata/err/0029_operation_definition_with_empty_selection_set.graphql new file mode 100644 index 00000000000..c7d2a3a5d59 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0029_operation_definition_with_empty_selection_set.graphql @@ -0,0 +1 @@ +query {} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0029_operation_definition_with_empty_selection_set.txt b/v3/lang-graphql/tests/query_testdata/err/0029_operation_definition_with_empty_selection_set.txt new file mode 100644 index 00000000000..d3b13e70466 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0029_operation_definition_with_empty_selection_set.txt @@ -0,0 +1,11 @@ +Err( + Positioned { + item: OtherError( + "At least one item must be specified", + ), + position: SourcePosition { + line: 1, + col: 8, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0030_operation_definition_with_description.graphql b/v3/lang-graphql/tests/query_testdata/err/0030_operation_definition_with_description.graphql new file mode 100644 index 00000000000..a653e1988c0 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0030_operation_definition_with_description.graphql @@ -0,0 +1,2 @@ +"after this PR this should not be an issue: https://github.com/graphql/graphql-spec/pull/892" +query empty {} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0030_operation_definition_with_description.txt b/v3/lang-graphql/tests/query_testdata/err/0030_operation_definition_with_description.txt new file mode 100644 index 00000000000..111d791122e --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0030_operation_definition_with_description.txt @@ -0,0 +1,32 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Keyword( + Query, + ), + Keyword( + Mutation, + ), + Keyword( + Subscription, + ), + Keyword( + Fragment, + ), + Punctuation( + BraceL, + ), + ], + found: Token( + String( + "after this PR this should not be an issue: https://github.com/graphql/graphql-spec/pull/892", + ), + ), + }, + position: SourcePosition { + line: 1, + col: 1, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0031_argument_with_erronous_string_value.graphql b/v3/lang-graphql/tests/query_testdata/err/0031_argument_with_erronous_string_value.graphql new file mode 100644 index 00000000000..0129fc372f3 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0031_argument_with_erronous_string_value.graphql @@ -0,0 +1,3 @@ +{ + user(id: "\string ID") +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0031_argument_with_erronous_string_value.txt b/v3/lang-graphql/tests/query_testdata/err/0031_argument_with_erronous_string_value.txt new file mode 100644 index 00000000000..1a5262d6826 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0031_argument_with_erronous_string_value.txt @@ -0,0 +1,39 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Number, + String, + Keyword( + True, + ), + Keyword( + False, + ), + Keyword( + Null, + ), + Punctuation( + Dollar, + ), + Punctuation( + BracketL, + ), + Punctuation( + BraceL, + ), + ], + found: LexerError( + InvalidString( + UnknownEscapeSequence( + "\\115", + ), + ), + ), + }, + position: SourcePosition { + line: 2, + col: 13, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0035_unterminated_string_value_in_object_value.graphql b/v3/lang-graphql/tests/query_testdata/err/0035_unterminated_string_value_in_object_value.graphql new file mode 100644 index 00000000000..cda40accd88 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0035_unterminated_string_value_in_object_value.graphql @@ -0,0 +1,7 @@ +mutation { + createStore(draft: { + name: [{ locale: "en", value: "my store }] + }) { + name(locale: "en") + } +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0035_unterminated_string_value_in_object_value.txt b/v3/lang-graphql/tests/query_testdata/err/0035_unterminated_string_value_in_object_value.txt new file mode 100644 index 00000000000..53969c536c5 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0035_unterminated_string_value_in_object_value.txt @@ -0,0 +1,37 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Number, + String, + Keyword( + True, + ), + Keyword( + False, + ), + Keyword( + Null, + ), + Punctuation( + Dollar, + ), + Punctuation( + BracketL, + ), + Punctuation( + BraceL, + ), + ], + found: LexerError( + InvalidString( + Unterminated, + ), + ), + }, + position: SourcePosition { + line: 3, + col: 47, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0040_operation_definition_missing_selection_set.graphql b/v3/lang-graphql/tests/query_testdata/err/0040_operation_definition_missing_selection_set.graphql new file mode 100644 index 00000000000..f72e8970a66 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0040_operation_definition_missing_selection_set.graphql @@ -0,0 +1 @@ +query __typename } \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0040_operation_definition_missing_selection_set.txt b/v3/lang-graphql/tests/query_testdata/err/0040_operation_definition_missing_selection_set.txt new file mode 100644 index 00000000000..b68921dfd2c --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0040_operation_definition_missing_selection_set.txt @@ -0,0 +1,20 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Punctuation( + BraceL, + ), + ], + found: Token( + Punctuation( + BraceR, + ), + ), + }, + position: SourcePosition { + line: 1, + col: 18, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0041_operation_definition_with_missing_selection_set.graphql b/v3/lang-graphql/tests/query_testdata/err/0041_operation_definition_with_missing_selection_set.graphql new file mode 100644 index 00000000000..d1f42f3a5ea --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0041_operation_definition_with_missing_selection_set.graphql @@ -0,0 +1 @@ +query __typename \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0041_operation_definition_with_missing_selection_set.txt b/v3/lang-graphql/tests/query_testdata/err/0041_operation_definition_with_missing_selection_set.txt new file mode 100644 index 00000000000..59d0f2a3f1a --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0041_operation_definition_with_missing_selection_set.txt @@ -0,0 +1,16 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Punctuation( + BraceL, + ), + ], + found: EndOfFile, + }, + position: SourcePosition { + line: 1, + col: 17, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0046_incomplete_spreads.graphql b/v3/lang-graphql/tests/query_testdata/err/0046_incomplete_spreads.graphql new file mode 100644 index 00000000000..09ac39cb1b9 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0046_incomplete_spreads.graphql @@ -0,0 +1 @@ +{ inner { ... }} diff --git a/v3/lang-graphql/tests/query_testdata/err/0046_incomplete_spreads.txt b/v3/lang-graphql/tests/query_testdata/err/0046_incomplete_spreads.txt new file mode 100644 index 00000000000..540a2fff416 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0046_incomplete_spreads.txt @@ -0,0 +1,18 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Name, + ], + found: Token( + Punctuation( + BraceR, + ), + ), + }, + position: SourcePosition { + line: 1, + col: 15, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0047_empty_variable_definition.graphql b/v3/lang-graphql/tests/query_testdata/err/0047_empty_variable_definition.graphql new file mode 100644 index 00000000000..a9361136b42 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0047_empty_variable_definition.graphql @@ -0,0 +1,3 @@ +query Op() { + field +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/0047_empty_variable_definition.txt b/v3/lang-graphql/tests/query_testdata/err/0047_empty_variable_definition.txt new file mode 100644 index 00000000000..a9fb7b087bc --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/0047_empty_variable_definition.txt @@ -0,0 +1,11 @@ +Err( + Positioned { + item: OtherError( + "At least one item must be specified", + ), + position: SourcePosition { + line: 1, + col: 10, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/1000_multibyte_chars_bad.graphql b/v3/lang-graphql/tests/query_testdata/err/1000_multibyte_chars_bad.graphql new file mode 100644 index 00000000000..b10c11ec6c8 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/1000_multibyte_chars_bad.graphql @@ -0,0 +1,2 @@ +# escape sequence not long enough (also make sure we don't read past end) +{ field(arg: "Has a \uA" diff --git a/v3/lang-graphql/tests/query_testdata/err/1000_multibyte_chars_bad.txt b/v3/lang-graphql/tests/query_testdata/err/1000_multibyte_chars_bad.txt new file mode 100644 index 00000000000..8129bd5e209 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/1000_multibyte_chars_bad.txt @@ -0,0 +1,37 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Number, + String, + Keyword( + True, + ), + Keyword( + False, + ), + Keyword( + Null, + ), + Punctuation( + Dollar, + ), + Punctuation( + BracketL, + ), + Punctuation( + BraceL, + ), + ], + found: LexerError( + InvalidString( + Unterminated, + ), + ), + }, + position: SourcePosition { + line: 2, + col: 21, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/1001_multibyte_chars_bad.graphql b/v3/lang-graphql/tests/query_testdata/err/1001_multibyte_chars_bad.graphql new file mode 100644 index 00000000000..d861b786329 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/1001_multibyte_chars_bad.graphql @@ -0,0 +1,2 @@ +# Non-hex unicode escape +{ field(arg: "Has a \u0A0Z multi-byte character.") } diff --git a/v3/lang-graphql/tests/query_testdata/err/1001_multibyte_chars_bad.txt b/v3/lang-graphql/tests/query_testdata/err/1001_multibyte_chars_bad.txt new file mode 100644 index 00000000000..ffb5a413889 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/1001_multibyte_chars_bad.txt @@ -0,0 +1,39 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Number, + String, + Keyword( + True, + ), + Keyword( + False, + ), + Keyword( + Null, + ), + Punctuation( + Dollar, + ), + Punctuation( + BracketL, + ), + Punctuation( + BraceL, + ), + ], + found: LexerError( + InvalidString( + InvalidUnicodeEscapeSequence( + "invalid hex digits", + ), + ), + ), + }, + position: SourcePosition { + line: 2, + col: 21, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/1002_multibyte_chars_bad.graphql b/v3/lang-graphql/tests/query_testdata/err/1002_multibyte_chars_bad.graphql new file mode 100644 index 00000000000..5ae73db1266 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/1002_multibyte_chars_bad.graphql @@ -0,0 +1,2 @@ +# invalid code point unicode escape (reserved high surrogate) +{ field(arg: "Has a \uD801 multi-byte character.") } diff --git a/v3/lang-graphql/tests/query_testdata/err/1002_multibyte_chars_bad.txt b/v3/lang-graphql/tests/query_testdata/err/1002_multibyte_chars_bad.txt new file mode 100644 index 00000000000..bc7c1cbdb73 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/1002_multibyte_chars_bad.txt @@ -0,0 +1,39 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Number, + String, + Keyword( + True, + ), + Keyword( + False, + ), + Keyword( + Null, + ), + Punctuation( + Dollar, + ), + Punctuation( + BracketL, + ), + Punctuation( + BraceL, + ), + ], + found: LexerError( + InvalidString( + InvalidUnicodeEscapeSequence( + "0xD801 is not a valid code point", + ), + ), + ), + }, + position: SourcePosition { + line: 2, + col: 21, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/9005_escaped_char.graphql b/v3/lang-graphql/tests/query_testdata/err/9005_escaped_char.graphql new file mode 100644 index 00000000000..1e9af5449cf --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/9005_escaped_char.graphql @@ -0,0 +1,5 @@ +{ + sku: "\a invalidly escaped" + stringValue: "\"properly escaped\"" + name: "\invalidly escaped\"" +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/9005_escaped_char.txt b/v3/lang-graphql/tests/query_testdata/err/9005_escaped_char.txt new file mode 100644 index 00000000000..94ce917a4f9 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/9005_escaped_char.txt @@ -0,0 +1,20 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Name, + ], + found: LexerError( + InvalidString( + UnknownEscapeSequence( + "\\97", + ), + ), + ), + }, + position: SourcePosition { + line: 2, + col: 11, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/9007_unterminated_string_value_in_object_value_argument.graphql b/v3/lang-graphql/tests/query_testdata/err/9007_unterminated_string_value_in_object_value_argument.graphql new file mode 100644 index 00000000000..cda40accd88 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/9007_unterminated_string_value_in_object_value_argument.graphql @@ -0,0 +1,7 @@ +mutation { + createStore(draft: { + name: [{ locale: "en", value: "my store }] + }) { + name(locale: "en") + } +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/9007_unterminated_string_value_in_object_value_argument.txt b/v3/lang-graphql/tests/query_testdata/err/9007_unterminated_string_value_in_object_value_argument.txt new file mode 100644 index 00000000000..53969c536c5 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/9007_unterminated_string_value_in_object_value_argument.txt @@ -0,0 +1,37 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Number, + String, + Keyword( + True, + ), + Keyword( + False, + ), + Keyword( + Null, + ), + Punctuation( + Dollar, + ), + Punctuation( + BracketL, + ), + Punctuation( + BraceL, + ), + ], + found: LexerError( + InvalidString( + Unterminated, + ), + ), + }, + position: SourcePosition { + line: 3, + col: 47, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/9008_unterminated_string_value.graphql b/v3/lang-graphql/tests/query_testdata/err/9008_unterminated_string_value.graphql new file mode 100644 index 00000000000..cc25b0c46b7 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/9008_unterminated_string_value.graphql @@ -0,0 +1,5 @@ +mutation { + createstore { + name(locale: "en) + } +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/err/9008_unterminated_string_value.txt b/v3/lang-graphql/tests/query_testdata/err/9008_unterminated_string_value.txt new file mode 100644 index 00000000000..d3552571e8a --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/err/9008_unterminated_string_value.txt @@ -0,0 +1,37 @@ +Err( + Positioned { + item: TokenError { + expected_tokens: [ + Number, + String, + Keyword( + True, + ), + Keyword( + False, + ), + Keyword( + Null, + ), + Punctuation( + Dollar, + ), + Punctuation( + BracketL, + ), + Punctuation( + BraceL, + ), + ], + found: LexerError( + InvalidString( + Unterminated, + ), + ), + }, + position: SourcePosition { + line: 3, + col: 22, + }, + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0001_empty.graphql b/v3/lang-graphql/tests/query_testdata/ok/0001_empty.graphql new file mode 100644 index 00000000000..e69de29bb2d diff --git a/v3/lang-graphql/tests/query_testdata/ok/0001_empty.txt b/v3/lang-graphql/tests/query_testdata/ok/0001_empty.txt new file mode 100644 index 00000000000..92aebe1581b --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0001_empty.txt @@ -0,0 +1,5 @@ +Ok( + ExecutableDocument { + items: [], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0002_selection_simple.graphql b/v3/lang-graphql/tests/query_testdata/ok/0002_selection_simple.graphql new file mode 100644 index 00000000000..c9cc21a2e5b --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0002_selection_simple.graphql @@ -0,0 +1,4 @@ +{ + pet + faveSnack +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0002_selection_simple.txt b/v3/lang-graphql/tests/query_testdata/ok/0002_selection_simple.txt new file mode 100644 index 00000000000..bdcce4a1d77 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0002_selection_simple.txt @@ -0,0 +1,100 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: None, + variable_definitions: None, + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "pet", + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 7, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 7, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "faveSnack", + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 13, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 13, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 4, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 4, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0003_selection_with_fields.graphql b/v3/lang-graphql/tests/query_testdata/ok/0003_selection_with_fields.graphql new file mode 100644 index 00000000000..325a85fdbf2 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0003_selection_with_fields.graphql @@ -0,0 +1,15 @@ + +{ + pet { + name + birthday { + month + day + } + playmates { + name + faveSnack + } + } + faveSnack +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0003_selection_with_fields.txt b/v3/lang-graphql/tests/query_testdata/ok/0003_selection_with_fields.txt new file mode 100644 index 00000000000..6703c0a6139 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0003_selection_with_fields.txt @@ -0,0 +1,362 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: None, + variable_definitions: None, + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "pet", + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 7, + }, + }, + arguments: None, + directives: [], + selection_set: Some( + Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "name", + ), + start: SourcePosition { + line: 4, + col: 9, + }, + end: SourcePosition { + line: 4, + col: 12, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 4, + col: 9, + }, + end: SourcePosition { + line: 4, + col: 12, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "birthday", + ), + start: SourcePosition { + line: 5, + col: 9, + }, + end: SourcePosition { + line: 5, + col: 16, + }, + }, + arguments: None, + directives: [], + selection_set: Some( + Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "month", + ), + start: SourcePosition { + line: 6, + col: 13, + }, + end: SourcePosition { + line: 6, + col: 17, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 6, + col: 13, + }, + end: SourcePosition { + line: 6, + col: 17, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "day", + ), + start: SourcePosition { + line: 7, + col: 13, + }, + end: SourcePosition { + line: 7, + col: 15, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 7, + col: 13, + }, + end: SourcePosition { + line: 7, + col: 15, + }, + }, + ], + }, + start: SourcePosition { + line: 5, + col: 18, + }, + end: SourcePosition { + line: 8, + col: 9, + }, + }, + ), + }, + ), + start: SourcePosition { + line: 5, + col: 9, + }, + end: SourcePosition { + line: 5, + col: 16, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "playmates", + ), + start: SourcePosition { + line: 9, + col: 9, + }, + end: SourcePosition { + line: 9, + col: 17, + }, + }, + arguments: None, + directives: [], + selection_set: Some( + Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "name", + ), + start: SourcePosition { + line: 10, + col: 13, + }, + end: SourcePosition { + line: 10, + col: 16, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 10, + col: 13, + }, + end: SourcePosition { + line: 10, + col: 16, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "faveSnack", + ), + start: SourcePosition { + line: 11, + col: 13, + }, + end: SourcePosition { + line: 11, + col: 21, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 11, + col: 13, + }, + end: SourcePosition { + line: 11, + col: 21, + }, + }, + ], + }, + start: SourcePosition { + line: 9, + col: 19, + }, + end: SourcePosition { + line: 12, + col: 9, + }, + }, + ), + }, + ), + start: SourcePosition { + line: 9, + col: 9, + }, + end: SourcePosition { + line: 9, + col: 17, + }, + }, + ], + }, + start: SourcePosition { + line: 3, + col: 9, + }, + end: SourcePosition { + line: 13, + col: 5, + }, + }, + ), + }, + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 7, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "faveSnack", + ), + start: SourcePosition { + line: 14, + col: 5, + }, + end: SourcePosition { + line: 14, + col: 13, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 14, + col: 5, + }, + end: SourcePosition { + line: 14, + col: 13, + }, + }, + ], + }, + start: SourcePosition { + line: 2, + col: 1, + }, + end: SourcePosition { + line: 15, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 2, + col: 1, + }, + end: SourcePosition { + line: 15, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0004_selection_with_fields_aliases_arguments.graphql b/v3/lang-graphql/tests/query_testdata/ok/0004_selection_with_fields_aliases_arguments.graphql new file mode 100644 index 00000000000..72b2349ff71 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0004_selection_with_fields_aliases_arguments.graphql @@ -0,0 +1,15 @@ + +{ + pet { + name: nickname + birthday { + month + day + } + playmates { + name + faveSnack + } + } + faveSnack(quantity: 4) +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0004_selection_with_fields_aliases_arguments.txt b/v3/lang-graphql/tests/query_testdata/ok/0004_selection_with_fields_aliases_arguments.txt new file mode 100644 index 00000000000..18d5f6f2da0 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0004_selection_with_fields_aliases_arguments.txt @@ -0,0 +1,431 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: None, + variable_definitions: None, + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "pet", + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 7, + }, + }, + arguments: None, + directives: [], + selection_set: Some( + Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: Some( + Spanning { + item: Alias( + Name( + "name", + ), + ), + start: SourcePosition { + line: 4, + col: 9, + }, + end: SourcePosition { + line: 4, + col: 12, + }, + }, + ), + name: Spanning { + item: Name( + "nickname", + ), + start: SourcePosition { + line: 4, + col: 15, + }, + end: SourcePosition { + line: 4, + col: 22, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 4, + col: 15, + }, + end: SourcePosition { + line: 4, + col: 22, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "birthday", + ), + start: SourcePosition { + line: 5, + col: 9, + }, + end: SourcePosition { + line: 5, + col: 16, + }, + }, + arguments: None, + directives: [], + selection_set: Some( + Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "month", + ), + start: SourcePosition { + line: 6, + col: 13, + }, + end: SourcePosition { + line: 6, + col: 17, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 6, + col: 13, + }, + end: SourcePosition { + line: 6, + col: 17, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "day", + ), + start: SourcePosition { + line: 7, + col: 13, + }, + end: SourcePosition { + line: 7, + col: 15, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 7, + col: 13, + }, + end: SourcePosition { + line: 7, + col: 15, + }, + }, + ], + }, + start: SourcePosition { + line: 5, + col: 18, + }, + end: SourcePosition { + line: 8, + col: 9, + }, + }, + ), + }, + ), + start: SourcePosition { + line: 5, + col: 9, + }, + end: SourcePosition { + line: 5, + col: 16, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "playmates", + ), + start: SourcePosition { + line: 9, + col: 9, + }, + end: SourcePosition { + line: 9, + col: 17, + }, + }, + arguments: None, + directives: [], + selection_set: Some( + Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "name", + ), + start: SourcePosition { + line: 10, + col: 13, + }, + end: SourcePosition { + line: 10, + col: 16, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 10, + col: 13, + }, + end: SourcePosition { + line: 10, + col: 16, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "faveSnack", + ), + start: SourcePosition { + line: 11, + col: 13, + }, + end: SourcePosition { + line: 11, + col: 21, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 11, + col: 13, + }, + end: SourcePosition { + line: 11, + col: 21, + }, + }, + ], + }, + start: SourcePosition { + line: 9, + col: 19, + }, + end: SourcePosition { + line: 12, + col: 9, + }, + }, + ), + }, + ), + start: SourcePosition { + line: 9, + col: 9, + }, + end: SourcePosition { + line: 9, + col: 17, + }, + }, + ], + }, + start: SourcePosition { + line: 3, + col: 9, + }, + end: SourcePosition { + line: 13, + col: 5, + }, + }, + ), + }, + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 7, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "faveSnack", + ), + start: SourcePosition { + line: 14, + col: 5, + }, + end: SourcePosition { + line: 14, + col: 13, + }, + }, + arguments: Some( + Spanning { + item: [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "quantity", + ), + start: SourcePosition { + line: 14, + col: 15, + }, + end: SourcePosition { + line: 14, + col: 22, + }, + }, + value: Spanning { + item: SimpleValue( + Integer( + 4, + ), + ), + start: SourcePosition { + line: 14, + col: 25, + }, + end: SourcePosition { + line: 14, + col: 25, + }, + }, + }, + start: SourcePosition { + line: 14, + col: 15, + }, + end: SourcePosition { + line: 14, + col: 25, + }, + }, + ], + start: SourcePosition { + line: 14, + col: 14, + }, + end: SourcePosition { + line: 14, + col: 26, + }, + }, + ), + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 14, + col: 5, + }, + end: SourcePosition { + line: 14, + col: 13, + }, + }, + ], + }, + start: SourcePosition { + line: 2, + col: 1, + }, + end: SourcePosition { + line: 15, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 2, + col: 1, + }, + end: SourcePosition { + line: 15, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0005_selection_with_inline_fragments.graphql b/v3/lang-graphql/tests/query_testdata/ok/0005_selection_with_inline_fragments.graphql new file mode 100644 index 00000000000..990d638829d --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0005_selection_with_inline_fragments.graphql @@ -0,0 +1,9 @@ +{ + animal + faveSnack + ... on Pet { + playmates { + count + } + } +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0005_selection_with_inline_fragments.txt b/v3/lang-graphql/tests/query_testdata/ok/0005_selection_with_inline_fragments.txt new file mode 100644 index 00000000000..d431f1e31b3 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0005_selection_with_inline_fragments.txt @@ -0,0 +1,235 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: None, + variable_definitions: None, + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "animal", + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 10, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 10, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "faveSnack", + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 13, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 13, + }, + }, + Spanning { + item: InlineFragment( + InlineFragment { + type_condition: Some( + Spanning { + item: TypeCondition { + on: Spanning { + item: TypeName( + Name( + "Pet", + ), + ), + start: SourcePosition { + line: 4, + col: 12, + }, + end: SourcePosition { + line: 4, + col: 14, + }, + }, + }, + start: SourcePosition { + line: 4, + col: 9, + }, + end: SourcePosition { + line: 4, + col: 14, + }, + }, + ), + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "playmates", + ), + start: SourcePosition { + line: 5, + col: 7, + }, + end: SourcePosition { + line: 5, + col: 15, + }, + }, + arguments: None, + directives: [], + selection_set: Some( + Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "count", + ), + start: SourcePosition { + line: 6, + col: 9, + }, + end: SourcePosition { + line: 6, + col: 13, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 6, + col: 9, + }, + end: SourcePosition { + line: 6, + col: 13, + }, + }, + ], + }, + start: SourcePosition { + line: 5, + col: 17, + }, + end: SourcePosition { + line: 7, + col: 7, + }, + }, + ), + }, + ), + start: SourcePosition { + line: 5, + col: 7, + }, + end: SourcePosition { + line: 5, + col: 15, + }, + }, + ], + }, + start: SourcePosition { + line: 4, + col: 16, + }, + end: SourcePosition { + line: 8, + col: 5, + }, + }, + }, + ), + start: SourcePosition { + line: 4, + col: 5, + }, + end: SourcePosition { + line: 8, + col: 5, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 9, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 9, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0006_selection_with_fragment_spread.graphql b/v3/lang-graphql/tests/query_testdata/ok/0006_selection_with_fragment_spread.graphql new file mode 100644 index 00000000000..cd0f34b5b79 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0006_selection_with_fragment_spread.graphql @@ -0,0 +1,15 @@ +{ + pet + ...snackSelection + ... on Nap { + cozyLocation + durationOfNap + } + ...snackSelection @deprecated + ... on Nap @provides(duration: "2 hours") { + cozyLocation + } + ... @J(N: 0) { + a + } +} diff --git a/v3/lang-graphql/tests/query_testdata/ok/0006_selection_with_fragment_spread.txt b/v3/lang-graphql/tests/query_testdata/ok/0006_selection_with_fragment_spread.txt new file mode 100644 index 00000000000..29d01847f5d --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0006_selection_with_fragment_spread.txt @@ -0,0 +1,582 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: None, + variable_definitions: None, + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "pet", + ), + start: SourcePosition { + line: 2, + col: 3, + }, + end: SourcePosition { + line: 2, + col: 5, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 2, + col: 3, + }, + end: SourcePosition { + line: 2, + col: 5, + }, + }, + Spanning { + item: FragmentSpread( + FragmentSpread { + fragment_name: Spanning { + item: Name( + "snackSelection", + ), + start: SourcePosition { + line: 3, + col: 6, + }, + end: SourcePosition { + line: 3, + col: 19, + }, + }, + directives: [], + }, + ), + start: SourcePosition { + line: 3, + col: 3, + }, + end: SourcePosition { + line: 3, + col: 19, + }, + }, + Spanning { + item: InlineFragment( + InlineFragment { + type_condition: Some( + Spanning { + item: TypeCondition { + on: Spanning { + item: TypeName( + Name( + "Nap", + ), + ), + start: SourcePosition { + line: 4, + col: 10, + }, + end: SourcePosition { + line: 4, + col: 12, + }, + }, + }, + start: SourcePosition { + line: 4, + col: 7, + }, + end: SourcePosition { + line: 4, + col: 12, + }, + }, + ), + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "cozyLocation", + ), + start: SourcePosition { + line: 5, + col: 5, + }, + end: SourcePosition { + line: 5, + col: 16, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 5, + col: 5, + }, + end: SourcePosition { + line: 5, + col: 16, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "durationOfNap", + ), + start: SourcePosition { + line: 6, + col: 5, + }, + end: SourcePosition { + line: 6, + col: 17, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 6, + col: 5, + }, + end: SourcePosition { + line: 6, + col: 17, + }, + }, + ], + }, + start: SourcePosition { + line: 4, + col: 14, + }, + end: SourcePosition { + line: 7, + col: 3, + }, + }, + }, + ), + start: SourcePosition { + line: 4, + col: 3, + }, + end: SourcePosition { + line: 7, + col: 3, + }, + }, + Spanning { + item: FragmentSpread( + FragmentSpread { + fragment_name: Spanning { + item: Name( + "snackSelection", + ), + start: SourcePosition { + line: 8, + col: 6, + }, + end: SourcePosition { + line: 8, + col: 19, + }, + }, + directives: [ + Spanning { + item: Directive { + name: Spanning { + item: Name( + "deprecated", + ), + start: SourcePosition { + line: 8, + col: 22, + }, + end: SourcePosition { + line: 8, + col: 31, + }, + }, + arguments: None, + }, + start: SourcePosition { + line: 8, + col: 21, + }, + end: SourcePosition { + line: 8, + col: 31, + }, + }, + ], + }, + ), + start: SourcePosition { + line: 8, + col: 3, + }, + end: SourcePosition { + line: 8, + col: 19, + }, + }, + Spanning { + item: InlineFragment( + InlineFragment { + type_condition: Some( + Spanning { + item: TypeCondition { + on: Spanning { + item: TypeName( + Name( + "Nap", + ), + ), + start: SourcePosition { + line: 9, + col: 10, + }, + end: SourcePosition { + line: 9, + col: 12, + }, + }, + }, + start: SourcePosition { + line: 9, + col: 7, + }, + end: SourcePosition { + line: 9, + col: 12, + }, + }, + ), + directives: [ + Spanning { + item: Directive { + name: Spanning { + item: Name( + "provides", + ), + start: SourcePosition { + line: 9, + col: 15, + }, + end: SourcePosition { + line: 9, + col: 22, + }, + }, + arguments: Some( + Spanning { + item: [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "duration", + ), + start: SourcePosition { + line: 9, + col: 24, + }, + end: SourcePosition { + line: 9, + col: 31, + }, + }, + value: Spanning { + item: SimpleValue( + String( + "2 hours", + ), + ), + start: SourcePosition { + line: 9, + col: 34, + }, + end: SourcePosition { + line: 9, + col: 42, + }, + }, + }, + start: SourcePosition { + line: 9, + col: 24, + }, + end: SourcePosition { + line: 9, + col: 42, + }, + }, + ], + start: SourcePosition { + line: 9, + col: 23, + }, + end: SourcePosition { + line: 9, + col: 43, + }, + }, + ), + }, + start: SourcePosition { + line: 9, + col: 14, + }, + end: SourcePosition { + line: 9, + col: 43, + }, + }, + ], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "cozyLocation", + ), + start: SourcePosition { + line: 10, + col: 5, + }, + end: SourcePosition { + line: 10, + col: 16, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 10, + col: 5, + }, + end: SourcePosition { + line: 10, + col: 16, + }, + }, + ], + }, + start: SourcePosition { + line: 9, + col: 45, + }, + end: SourcePosition { + line: 11, + col: 3, + }, + }, + }, + ), + start: SourcePosition { + line: 9, + col: 3, + }, + end: SourcePosition { + line: 11, + col: 3, + }, + }, + Spanning { + item: InlineFragment( + InlineFragment { + type_condition: None, + directives: [ + Spanning { + item: Directive { + name: Spanning { + item: Name( + "J", + ), + start: SourcePosition { + line: 12, + col: 8, + }, + end: SourcePosition { + line: 12, + col: 8, + }, + }, + arguments: Some( + Spanning { + item: [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "N", + ), + start: SourcePosition { + line: 12, + col: 10, + }, + end: SourcePosition { + line: 12, + col: 10, + }, + }, + value: Spanning { + item: SimpleValue( + Integer( + 0, + ), + ), + start: SourcePosition { + line: 12, + col: 13, + }, + end: SourcePosition { + line: 12, + col: 13, + }, + }, + }, + start: SourcePosition { + line: 12, + col: 10, + }, + end: SourcePosition { + line: 12, + col: 13, + }, + }, + ], + start: SourcePosition { + line: 12, + col: 9, + }, + end: SourcePosition { + line: 12, + col: 14, + }, + }, + ), + }, + start: SourcePosition { + line: 12, + col: 7, + }, + end: SourcePosition { + line: 12, + col: 14, + }, + }, + ], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "a", + ), + start: SourcePosition { + line: 13, + col: 5, + }, + end: SourcePosition { + line: 13, + col: 5, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 13, + col: 5, + }, + end: SourcePosition { + line: 13, + col: 5, + }, + }, + ], + }, + start: SourcePosition { + line: 12, + col: 16, + }, + end: SourcePosition { + line: 14, + col: 3, + }, + }, + }, + ), + start: SourcePosition { + line: 12, + col: 3, + }, + end: SourcePosition { + line: 14, + col: 3, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 15, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 15, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0012_fragment_definition.graphql b/v3/lang-graphql/tests/query_testdata/ok/0012_fragment_definition.graphql new file mode 100644 index 00000000000..91b444c5cba --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0012_fragment_definition.graphql @@ -0,0 +1,5 @@ +fragment friendFields on User @example { + id + name + profilePic(size: 50) +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0012_fragment_definition.txt b/v3/lang-graphql/tests/query_testdata/ok/0012_fragment_definition.txt new file mode 100644 index 00000000000..e01e623ee39 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0012_fragment_definition.txt @@ -0,0 +1,248 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Fragment( + FragmentDefinition { + name: Spanning { + item: Name( + "friendFields", + ), + start: SourcePosition { + line: 1, + col: 10, + }, + end: SourcePosition { + line: 1, + col: 21, + }, + }, + type_condition: Spanning { + item: TypeCondition { + on: Spanning { + item: TypeName( + Name( + "User", + ), + ), + start: SourcePosition { + line: 1, + col: 26, + }, + end: SourcePosition { + line: 1, + col: 29, + }, + }, + }, + start: SourcePosition { + line: 1, + col: 23, + }, + end: SourcePosition { + line: 1, + col: 29, + }, + }, + directives: [ + Spanning { + item: Directive { + name: Spanning { + item: Name( + "example", + ), + start: SourcePosition { + line: 1, + col: 32, + }, + end: SourcePosition { + line: 1, + col: 38, + }, + }, + arguments: None, + }, + start: SourcePosition { + line: 1, + col: 31, + }, + end: SourcePosition { + line: 1, + col: 38, + }, + }, + ], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "id", + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 6, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 6, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "name", + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 8, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 8, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "profilePic", + ), + start: SourcePosition { + line: 4, + col: 5, + }, + end: SourcePosition { + line: 4, + col: 14, + }, + }, + arguments: Some( + Spanning { + item: [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "size", + ), + start: SourcePosition { + line: 4, + col: 16, + }, + end: SourcePosition { + line: 4, + col: 19, + }, + }, + value: Spanning { + item: SimpleValue( + Integer( + 50, + ), + ), + start: SourcePosition { + line: 4, + col: 22, + }, + end: SourcePosition { + line: 4, + col: 23, + }, + }, + }, + start: SourcePosition { + line: 4, + col: 16, + }, + end: SourcePosition { + line: 4, + col: 23, + }, + }, + ], + start: SourcePosition { + line: 4, + col: 15, + }, + end: SourcePosition { + line: 4, + col: 24, + }, + }, + ), + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 4, + col: 5, + }, + end: SourcePosition { + line: 4, + col: 14, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 40, + }, + end: SourcePosition { + line: 5, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 5, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0013_fragment_definition_with_fragment_spread.graphql b/v3/lang-graphql/tests/query_testdata/ok/0013_fragment_definition_with_fragment_spread.graphql new file mode 100644 index 00000000000..38f9a388857 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0013_fragment_definition_with_fragment_spread.graphql @@ -0,0 +1,5 @@ +fragment friendFields on User { + id + name + ...standardProfilePic +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0013_fragment_definition_with_fragment_spread.txt b/v3/lang-graphql/tests/query_testdata/ok/0013_fragment_definition_with_fragment_spread.txt new file mode 100644 index 00000000000..e19800e42c8 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0013_fragment_definition_with_fragment_spread.txt @@ -0,0 +1,165 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Fragment( + FragmentDefinition { + name: Spanning { + item: Name( + "friendFields", + ), + start: SourcePosition { + line: 1, + col: 10, + }, + end: SourcePosition { + line: 1, + col: 21, + }, + }, + type_condition: Spanning { + item: TypeCondition { + on: Spanning { + item: TypeName( + Name( + "User", + ), + ), + start: SourcePosition { + line: 1, + col: 26, + }, + end: SourcePosition { + line: 1, + col: 29, + }, + }, + }, + start: SourcePosition { + line: 1, + col: 23, + }, + end: SourcePosition { + line: 1, + col: 29, + }, + }, + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "id", + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 6, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 6, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "name", + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 8, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 8, + }, + }, + Spanning { + item: FragmentSpread( + FragmentSpread { + fragment_name: Spanning { + item: Name( + "standardProfilePic", + ), + start: SourcePosition { + line: 4, + col: 8, + }, + end: SourcePosition { + line: 4, + col: 25, + }, + }, + directives: [], + }, + ), + start: SourcePosition { + line: 4, + col: 5, + }, + end: SourcePosition { + line: 4, + col: 25, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 31, + }, + end: SourcePosition { + line: 5, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 5, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0020_operation_type_definition.graphql b/v3/lang-graphql/tests/query_testdata/ok/0020_operation_type_definition.graphql new file mode 100644 index 00000000000..e149e4bfb6a --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0020_operation_type_definition.graphql @@ -0,0 +1,9 @@ +query myQuery { + animal: cat + dog { + panda { + anotherCat @deprecated + } + } + lion +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0020_operation_type_definition.txt b/v3/lang-graphql/tests/query_testdata/ok/0020_operation_type_definition.txt new file mode 100644 index 00000000000..837bd52773e --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0020_operation_type_definition.txt @@ -0,0 +1,280 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: Some( + Spanning { + item: Name( + "myQuery", + ), + start: SourcePosition { + line: 1, + col: 7, + }, + end: SourcePosition { + line: 1, + col: 13, + }, + }, + ), + variable_definitions: None, + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: Some( + Spanning { + item: Alias( + Name( + "animal", + ), + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 10, + }, + }, + ), + name: Spanning { + item: Name( + "cat", + ), + start: SourcePosition { + line: 2, + col: 13, + }, + end: SourcePosition { + line: 2, + col: 15, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 2, + col: 13, + }, + end: SourcePosition { + line: 2, + col: 15, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "dog", + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 7, + }, + }, + arguments: None, + directives: [], + selection_set: Some( + Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "panda", + ), + start: SourcePosition { + line: 4, + col: 9, + }, + end: SourcePosition { + line: 4, + col: 13, + }, + }, + arguments: None, + directives: [], + selection_set: Some( + Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "anotherCat", + ), + start: SourcePosition { + line: 5, + col: 13, + }, + end: SourcePosition { + line: 5, + col: 22, + }, + }, + arguments: None, + directives: [ + Spanning { + item: Directive { + name: Spanning { + item: Name( + "deprecated", + ), + start: SourcePosition { + line: 5, + col: 25, + }, + end: SourcePosition { + line: 5, + col: 34, + }, + }, + arguments: None, + }, + start: SourcePosition { + line: 5, + col: 24, + }, + end: SourcePosition { + line: 5, + col: 34, + }, + }, + ], + selection_set: None, + }, + ), + start: SourcePosition { + line: 5, + col: 13, + }, + end: SourcePosition { + line: 5, + col: 22, + }, + }, + ], + }, + start: SourcePosition { + line: 4, + col: 15, + }, + end: SourcePosition { + line: 6, + col: 9, + }, + }, + ), + }, + ), + start: SourcePosition { + line: 4, + col: 9, + }, + end: SourcePosition { + line: 4, + col: 13, + }, + }, + ], + }, + start: SourcePosition { + line: 3, + col: 9, + }, + end: SourcePosition { + line: 7, + col: 5, + }, + }, + ), + }, + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 7, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "lion", + ), + start: SourcePosition { + line: 8, + col: 5, + }, + end: SourcePosition { + line: 8, + col: 8, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 8, + col: 5, + }, + end: SourcePosition { + line: 8, + col: 8, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 15, + }, + end: SourcePosition { + line: 9, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 9, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0021_operation_type_definition_with_arguments.graphql b/v3/lang-graphql/tests/query_testdata/ok/0021_operation_type_definition_with_arguments.graphql new file mode 100644 index 00000000000..d9785528424 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0021_operation_type_definition_with_arguments.graphql @@ -0,0 +1,4 @@ +query myQuery($var: input $varOther: otherInput){ + animal + treat +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0021_operation_type_definition_with_arguments.txt b/v3/lang-graphql/tests/query_testdata/ok/0021_operation_type_definition_with_arguments.txt new file mode 100644 index 00000000000..cdf8f65ac0a --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0021_operation_type_definition_with_arguments.txt @@ -0,0 +1,219 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: Some( + Spanning { + item: Name( + "myQuery", + ), + start: SourcePosition { + line: 1, + col: 7, + }, + end: SourcePosition { + line: 1, + col: 13, + }, + }, + ), + variable_definitions: Some( + Spanning { + item: [ + Spanning { + item: VariableDefinition { + name: Spanning { + item: Name( + "var", + ), + start: SourcePosition { + line: 1, + col: 16, + }, + end: SourcePosition { + line: 1, + col: 18, + }, + }, + var_type: Spanning { + item: TypeContainer { + base: Named( + TypeName( + Name( + "input", + ), + ), + ), + nullable: true, + }, + start: SourcePosition { + line: 1, + col: 21, + }, + end: SourcePosition { + line: 1, + col: 25, + }, + }, + default_value: None, + }, + start: SourcePosition { + line: 1, + col: 15, + }, + end: SourcePosition { + line: 1, + col: 25, + }, + }, + Spanning { + item: VariableDefinition { + name: Spanning { + item: Name( + "varOther", + ), + start: SourcePosition { + line: 1, + col: 28, + }, + end: SourcePosition { + line: 1, + col: 35, + }, + }, + var_type: Spanning { + item: TypeContainer { + base: Named( + TypeName( + Name( + "otherInput", + ), + ), + ), + nullable: true, + }, + start: SourcePosition { + line: 1, + col: 38, + }, + end: SourcePosition { + line: 1, + col: 47, + }, + }, + default_value: None, + }, + start: SourcePosition { + line: 1, + col: 27, + }, + end: SourcePosition { + line: 1, + col: 47, + }, + }, + ], + start: SourcePosition { + line: 1, + col: 14, + }, + end: SourcePosition { + line: 1, + col: 48, + }, + }, + ), + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "animal", + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 10, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 10, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "treat", + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 9, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 9, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 49, + }, + end: SourcePosition { + line: 4, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 4, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0022_operation_type_definition_with_arguments_and_directives.graphql b/v3/lang-graphql/tests/query_testdata/ok/0022_operation_type_definition_with_arguments_and_directives.graphql new file mode 100644 index 00000000000..3967a5ed425 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0022_operation_type_definition_with_arguments_and_directives.graphql @@ -0,0 +1,4 @@ +query myQuery($var: input $varOther: otherInput) @deprecated @unused { + animal + treat +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0022_operation_type_definition_with_arguments_and_directives.txt b/v3/lang-graphql/tests/query_testdata/ok/0022_operation_type_definition_with_arguments_and_directives.txt new file mode 100644 index 00000000000..4fe1b292174 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0022_operation_type_definition_with_arguments_and_directives.txt @@ -0,0 +1,272 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: Some( + Spanning { + item: Name( + "myQuery", + ), + start: SourcePosition { + line: 1, + col: 7, + }, + end: SourcePosition { + line: 1, + col: 13, + }, + }, + ), + variable_definitions: Some( + Spanning { + item: [ + Spanning { + item: VariableDefinition { + name: Spanning { + item: Name( + "var", + ), + start: SourcePosition { + line: 1, + col: 16, + }, + end: SourcePosition { + line: 1, + col: 18, + }, + }, + var_type: Spanning { + item: TypeContainer { + base: Named( + TypeName( + Name( + "input", + ), + ), + ), + nullable: true, + }, + start: SourcePosition { + line: 1, + col: 21, + }, + end: SourcePosition { + line: 1, + col: 25, + }, + }, + default_value: None, + }, + start: SourcePosition { + line: 1, + col: 15, + }, + end: SourcePosition { + line: 1, + col: 25, + }, + }, + Spanning { + item: VariableDefinition { + name: Spanning { + item: Name( + "varOther", + ), + start: SourcePosition { + line: 1, + col: 28, + }, + end: SourcePosition { + line: 1, + col: 35, + }, + }, + var_type: Spanning { + item: TypeContainer { + base: Named( + TypeName( + Name( + "otherInput", + ), + ), + ), + nullable: true, + }, + start: SourcePosition { + line: 1, + col: 38, + }, + end: SourcePosition { + line: 1, + col: 47, + }, + }, + default_value: None, + }, + start: SourcePosition { + line: 1, + col: 27, + }, + end: SourcePosition { + line: 1, + col: 47, + }, + }, + ], + start: SourcePosition { + line: 1, + col: 14, + }, + end: SourcePosition { + line: 1, + col: 48, + }, + }, + ), + directives: [ + Spanning { + item: Directive { + name: Spanning { + item: Name( + "deprecated", + ), + start: SourcePosition { + line: 1, + col: 51, + }, + end: SourcePosition { + line: 1, + col: 60, + }, + }, + arguments: None, + }, + start: SourcePosition { + line: 1, + col: 50, + }, + end: SourcePosition { + line: 1, + col: 60, + }, + }, + Spanning { + item: Directive { + name: Spanning { + item: Name( + "unused", + ), + start: SourcePosition { + line: 1, + col: 63, + }, + end: SourcePosition { + line: 1, + col: 68, + }, + }, + arguments: None, + }, + start: SourcePosition { + line: 1, + col: 62, + }, + end: SourcePosition { + line: 1, + col: 68, + }, + }, + ], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "animal", + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 10, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 10, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "treat", + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 9, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 9, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 70, + }, + end: SourcePosition { + line: 4, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 4, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0030_values.graphql b/v3/lang-graphql/tests/query_testdata/ok/0030_values.graphql new file mode 100644 index 00000000000..24065052149 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0030_values.graphql @@ -0,0 +1,11 @@ +{ + user( + id: 4, + size: $size + value: "string", + input: [ "one", 1.34 ], + otherInput: { key: false, output: null } + emptyList: [] + emptyObject: {} + ) +} diff --git a/v3/lang-graphql/tests/query_testdata/ok/0030_values.txt b/v3/lang-graphql/tests/query_testdata/ok/0030_values.txt new file mode 100644 index 00000000000..8b366b8ab3b --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0030_values.txt @@ -0,0 +1,464 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: None, + variable_definitions: None, + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "user", + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 8, + }, + }, + arguments: Some( + Spanning { + item: [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "id", + ), + start: SourcePosition { + line: 3, + col: 9, + }, + end: SourcePosition { + line: 3, + col: 10, + }, + }, + value: Spanning { + item: SimpleValue( + Integer( + 4, + ), + ), + start: SourcePosition { + line: 3, + col: 13, + }, + end: SourcePosition { + line: 3, + col: 13, + }, + }, + }, + start: SourcePosition { + line: 3, + col: 9, + }, + end: SourcePosition { + line: 3, + col: 13, + }, + }, + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "size", + ), + start: SourcePosition { + line: 4, + col: 9, + }, + end: SourcePosition { + line: 4, + col: 12, + }, + }, + value: Spanning { + item: Variable( + Name( + "size", + ), + ), + start: SourcePosition { + line: 4, + col: 15, + }, + end: SourcePosition { + line: 4, + col: 19, + }, + }, + }, + start: SourcePosition { + line: 4, + col: 9, + }, + end: SourcePosition { + line: 4, + col: 19, + }, + }, + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "value", + ), + start: SourcePosition { + line: 5, + col: 9, + }, + end: SourcePosition { + line: 5, + col: 13, + }, + }, + value: Spanning { + item: SimpleValue( + String( + "string", + ), + ), + start: SourcePosition { + line: 5, + col: 16, + }, + end: SourcePosition { + line: 5, + col: 23, + }, + }, + }, + start: SourcePosition { + line: 5, + col: 9, + }, + end: SourcePosition { + line: 5, + col: 23, + }, + }, + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "input", + ), + start: SourcePosition { + line: 6, + col: 9, + }, + end: SourcePosition { + line: 6, + col: 13, + }, + }, + value: Spanning { + item: List( + [ + Spanning { + item: SimpleValue( + String( + "one", + ), + ), + start: SourcePosition { + line: 6, + col: 18, + }, + end: SourcePosition { + line: 6, + col: 22, + }, + }, + Spanning { + item: SimpleValue( + Float( + 1.34, + ), + ), + start: SourcePosition { + line: 6, + col: 25, + }, + end: SourcePosition { + line: 6, + col: 28, + }, + }, + ], + ), + start: SourcePosition { + line: 6, + col: 16, + }, + end: SourcePosition { + line: 6, + col: 30, + }, + }, + }, + start: SourcePosition { + line: 6, + col: 9, + }, + end: SourcePosition { + line: 6, + col: 30, + }, + }, + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "otherInput", + ), + start: SourcePosition { + line: 7, + col: 9, + }, + end: SourcePosition { + line: 7, + col: 18, + }, + }, + value: Spanning { + item: Object( + [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "key", + ), + start: SourcePosition { + line: 7, + col: 23, + }, + end: SourcePosition { + line: 7, + col: 25, + }, + }, + value: Spanning { + item: SimpleValue( + Boolean( + false, + ), + ), + start: SourcePosition { + line: 7, + col: 28, + }, + end: SourcePosition { + line: 7, + col: 32, + }, + }, + }, + start: SourcePosition { + line: 7, + col: 23, + }, + end: SourcePosition { + line: 7, + col: 32, + }, + }, + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "output", + ), + start: SourcePosition { + line: 7, + col: 35, + }, + end: SourcePosition { + line: 7, + col: 40, + }, + }, + value: Spanning { + item: SimpleValue( + Null, + ), + start: SourcePosition { + line: 7, + col: 43, + }, + end: SourcePosition { + line: 7, + col: 46, + }, + }, + }, + start: SourcePosition { + line: 7, + col: 35, + }, + end: SourcePosition { + line: 7, + col: 46, + }, + }, + ], + ), + start: SourcePosition { + line: 7, + col: 21, + }, + end: SourcePosition { + line: 7, + col: 48, + }, + }, + }, + start: SourcePosition { + line: 7, + col: 9, + }, + end: SourcePosition { + line: 7, + col: 48, + }, + }, + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "emptyList", + ), + start: SourcePosition { + line: 8, + col: 9, + }, + end: SourcePosition { + line: 8, + col: 17, + }, + }, + value: Spanning { + item: List( + [], + ), + start: SourcePosition { + line: 8, + col: 20, + }, + end: SourcePosition { + line: 8, + col: 21, + }, + }, + }, + start: SourcePosition { + line: 8, + col: 9, + }, + end: SourcePosition { + line: 8, + col: 21, + }, + }, + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "emptyObject", + ), + start: SourcePosition { + line: 9, + col: 9, + }, + end: SourcePosition { + line: 9, + col: 19, + }, + }, + value: Spanning { + item: Object( + [], + ), + start: SourcePosition { + line: 9, + col: 22, + }, + end: SourcePosition { + line: 9, + col: 23, + }, + }, + }, + start: SourcePosition { + line: 9, + col: 9, + }, + end: SourcePosition { + line: 9, + col: 23, + }, + }, + ], + start: SourcePosition { + line: 2, + col: 9, + }, + end: SourcePosition { + line: 10, + col: 5, + }, + }, + ), + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 8, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 11, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 11, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0031_variables_with_default.graphql b/v3/lang-graphql/tests/query_testdata/ok/0031_variables_with_default.graphql new file mode 100644 index 00000000000..84d0d59c628 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0031_variables_with_default.graphql @@ -0,0 +1,3 @@ +query getOutput($input: Int = 5 $config: String = "Config") { + animal +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0031_variables_with_default.txt b/v3/lang-graphql/tests/query_testdata/ok/0031_variables_with_default.txt new file mode 100644 index 00000000000..7b838a32ac6 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0031_variables_with_default.txt @@ -0,0 +1,220 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: Some( + Spanning { + item: Name( + "getOutput", + ), + start: SourcePosition { + line: 1, + col: 7, + }, + end: SourcePosition { + line: 1, + col: 15, + }, + }, + ), + variable_definitions: Some( + Spanning { + item: [ + Spanning { + item: VariableDefinition { + name: Spanning { + item: Name( + "input", + ), + start: SourcePosition { + line: 1, + col: 18, + }, + end: SourcePosition { + line: 1, + col: 22, + }, + }, + var_type: Spanning { + item: TypeContainer { + base: Named( + TypeName( + Name( + "Int", + ), + ), + ), + nullable: true, + }, + start: SourcePosition { + line: 1, + col: 25, + }, + end: SourcePosition { + line: 1, + col: 27, + }, + }, + default_value: Some( + Spanning { + item: SimpleValue( + Integer( + 5, + ), + ), + start: SourcePosition { + line: 1, + col: 31, + }, + end: SourcePosition { + line: 1, + col: 31, + }, + }, + ), + }, + start: SourcePosition { + line: 1, + col: 17, + }, + end: SourcePosition { + line: 1, + col: 31, + }, + }, + Spanning { + item: VariableDefinition { + name: Spanning { + item: Name( + "config", + ), + start: SourcePosition { + line: 1, + col: 34, + }, + end: SourcePosition { + line: 1, + col: 39, + }, + }, + var_type: Spanning { + item: TypeContainer { + base: Named( + TypeName( + Name( + "String", + ), + ), + ), + nullable: true, + }, + start: SourcePosition { + line: 1, + col: 42, + }, + end: SourcePosition { + line: 1, + col: 47, + }, + }, + default_value: Some( + Spanning { + item: SimpleValue( + String( + "Config", + ), + ), + start: SourcePosition { + line: 1, + col: 51, + }, + end: SourcePosition { + line: 1, + col: 58, + }, + }, + ), + }, + start: SourcePosition { + line: 1, + col: 33, + }, + end: SourcePosition { + line: 1, + col: 58, + }, + }, + ], + start: SourcePosition { + line: 1, + col: 16, + }, + end: SourcePosition { + line: 1, + col: 59, + }, + }, + ), + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "animal", + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 10, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 10, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 61, + }, + end: SourcePosition { + line: 3, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 3, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0034_query_shorthand_followed_by_fragment_definition.graphql b/v3/lang-graphql/tests/query_testdata/ok/0034_query_shorthand_followed_by_fragment_definition.graphql new file mode 100644 index 00000000000..2fc07e5fbb1 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0034_query_shorthand_followed_by_fragment_definition.graphql @@ -0,0 +1,8 @@ +{ + ...friendFields +} + +fragment friendFields on User { + id + name +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0034_query_shorthand_followed_by_fragment_definition.txt b/v3/lang-graphql/tests/query_testdata/ok/0034_query_shorthand_followed_by_fragment_definition.txt new file mode 100644 index 00000000000..76c0016a93b --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0034_query_shorthand_followed_by_fragment_definition.txt @@ -0,0 +1,197 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: None, + variable_definitions: None, + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: FragmentSpread( + FragmentSpread { + fragment_name: Spanning { + item: Name( + "friendFields", + ), + start: SourcePosition { + line: 2, + col: 6, + }, + end: SourcePosition { + line: 2, + col: 17, + }, + }, + directives: [], + }, + ), + start: SourcePosition { + line: 2, + col: 3, + }, + end: SourcePosition { + line: 2, + col: 17, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 3, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 3, + col: 1, + }, + }, + Spanning { + item: Fragment( + FragmentDefinition { + name: Spanning { + item: Name( + "friendFields", + ), + start: SourcePosition { + line: 5, + col: 10, + }, + end: SourcePosition { + line: 5, + col: 21, + }, + }, + type_condition: Spanning { + item: TypeCondition { + on: Spanning { + item: TypeName( + Name( + "User", + ), + ), + start: SourcePosition { + line: 5, + col: 26, + }, + end: SourcePosition { + line: 5, + col: 29, + }, + }, + }, + start: SourcePosition { + line: 5, + col: 23, + }, + end: SourcePosition { + line: 5, + col: 29, + }, + }, + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "id", + ), + start: SourcePosition { + line: 6, + col: 3, + }, + end: SourcePosition { + line: 6, + col: 4, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 6, + col: 3, + }, + end: SourcePosition { + line: 6, + col: 4, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "name", + ), + start: SourcePosition { + line: 7, + col: 3, + }, + end: SourcePosition { + line: 7, + col: 6, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 7, + col: 3, + }, + end: SourcePosition { + line: 7, + col: 6, + }, + }, + ], + }, + start: SourcePosition { + line: 5, + col: 31, + }, + end: SourcePosition { + line: 8, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 5, + col: 1, + }, + end: SourcePosition { + line: 8, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0035_query_with_variables.graphql b/v3/lang-graphql/tests/query_testdata/ok/0035_query_with_variables.graphql new file mode 100644 index 00000000000..99eb457ed65 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0035_query_with_variables.graphql @@ -0,0 +1,3 @@ +query Foo($bar: Int) { + name +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0035_query_with_variables.txt b/v3/lang-graphql/tests/query_testdata/ok/0035_query_with_variables.txt new file mode 100644 index 00000000000..a5d3a119e18 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0035_query_with_variables.txt @@ -0,0 +1,142 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: Some( + Spanning { + item: Name( + "Foo", + ), + start: SourcePosition { + line: 1, + col: 7, + }, + end: SourcePosition { + line: 1, + col: 9, + }, + }, + ), + variable_definitions: Some( + Spanning { + item: [ + Spanning { + item: VariableDefinition { + name: Spanning { + item: Name( + "bar", + ), + start: SourcePosition { + line: 1, + col: 12, + }, + end: SourcePosition { + line: 1, + col: 14, + }, + }, + var_type: Spanning { + item: TypeContainer { + base: Named( + TypeName( + Name( + "Int", + ), + ), + ), + nullable: true, + }, + start: SourcePosition { + line: 1, + col: 17, + }, + end: SourcePosition { + line: 1, + col: 19, + }, + }, + default_value: None, + }, + start: SourcePosition { + line: 1, + col: 11, + }, + end: SourcePosition { + line: 1, + col: 19, + }, + }, + ], + start: SourcePosition { + line: 1, + col: 10, + }, + end: SourcePosition { + line: 1, + col: 20, + }, + }, + ), + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "name", + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 8, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 8, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 22, + }, + end: SourcePosition { + line: 3, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 3, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0036_parses_variable_definition_with_list_type.graphql b/v3/lang-graphql/tests/query_testdata/ok/0036_parses_variable_definition_with_list_type.graphql new file mode 100644 index 00000000000..697d332005f --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0036_parses_variable_definition_with_list_type.graphql @@ -0,0 +1,4 @@ +query ($height: [Int]) { + id + trees(height: $height) +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0036_parses_variable_definition_with_list_type.txt b/v3/lang-graphql/tests/query_testdata/ok/0036_parses_variable_definition_with_list_type.txt new file mode 100644 index 00000000000..b8bb9b7233b --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0036_parses_variable_definition_with_list_type.txt @@ -0,0 +1,217 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: None, + variable_definitions: Some( + Spanning { + item: [ + Spanning { + item: VariableDefinition { + name: Spanning { + item: Name( + "height", + ), + start: SourcePosition { + line: 1, + col: 9, + }, + end: SourcePosition { + line: 1, + col: 14, + }, + }, + var_type: Spanning { + item: TypeContainer { + base: List( + TypeContainer { + base: Named( + TypeName( + Name( + "Int", + ), + ), + ), + nullable: true, + }, + ), + nullable: true, + }, + start: SourcePosition { + line: 1, + col: 17, + }, + end: SourcePosition { + line: 1, + col: 21, + }, + }, + default_value: None, + }, + start: SourcePosition { + line: 1, + col: 8, + }, + end: SourcePosition { + line: 1, + col: 21, + }, + }, + ], + start: SourcePosition { + line: 1, + col: 7, + }, + end: SourcePosition { + line: 1, + col: 22, + }, + }, + ), + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "id", + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 6, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 2, + col: 5, + }, + end: SourcePosition { + line: 2, + col: 6, + }, + }, + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "trees", + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 9, + }, + }, + arguments: Some( + Spanning { + item: [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "height", + ), + start: SourcePosition { + line: 3, + col: 11, + }, + end: SourcePosition { + line: 3, + col: 16, + }, + }, + value: Spanning { + item: Variable( + Name( + "height", + ), + ), + start: SourcePosition { + line: 3, + col: 19, + }, + end: SourcePosition { + line: 3, + col: 25, + }, + }, + }, + start: SourcePosition { + line: 3, + col: 11, + }, + end: SourcePosition { + line: 3, + col: 25, + }, + }, + ], + start: SourcePosition { + line: 3, + col: 10, + }, + end: SourcePosition { + line: 3, + col: 26, + }, + }, + ), + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 9, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 24, + }, + end: SourcePosition { + line: 4, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 4, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0037_operation_type_definition_with_inline_fragment.graphql b/v3/lang-graphql/tests/query_testdata/ok/0037_operation_type_definition_with_inline_fragment.graphql new file mode 100644 index 00000000000..314fff8a1ff --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0037_operation_type_definition_with_inline_fragment.graphql @@ -0,0 +1,16 @@ +query SomeQuery( + $param1: String! + $param2: String! +) { + item1( + param1: $param1 + param2: $param2 + ) { + id + ... on Fragment1 { + field3 { + field4 + } + } + } +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0037_operation_type_definition_with_inline_fragment.txt b/v3/lang-graphql/tests/query_testdata/ok/0037_operation_type_definition_with_inline_fragment.txt new file mode 100644 index 00000000000..b4bd03c5b79 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0037_operation_type_definition_with_inline_fragment.txt @@ -0,0 +1,462 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: Some( + Spanning { + item: Name( + "SomeQuery", + ), + start: SourcePosition { + line: 1, + col: 7, + }, + end: SourcePosition { + line: 1, + col: 15, + }, + }, + ), + variable_definitions: Some( + Spanning { + item: [ + Spanning { + item: VariableDefinition { + name: Spanning { + item: Name( + "param1", + ), + start: SourcePosition { + line: 2, + col: 4, + }, + end: SourcePosition { + line: 2, + col: 9, + }, + }, + var_type: Spanning { + item: TypeContainer { + base: Named( + TypeName( + Name( + "String", + ), + ), + ), + nullable: false, + }, + start: SourcePosition { + line: 2, + col: 12, + }, + end: SourcePosition { + line: 2, + col: 18, + }, + }, + default_value: None, + }, + start: SourcePosition { + line: 2, + col: 3, + }, + end: SourcePosition { + line: 2, + col: 18, + }, + }, + Spanning { + item: VariableDefinition { + name: Spanning { + item: Name( + "param2", + ), + start: SourcePosition { + line: 3, + col: 4, + }, + end: SourcePosition { + line: 3, + col: 9, + }, + }, + var_type: Spanning { + item: TypeContainer { + base: Named( + TypeName( + Name( + "String", + ), + ), + ), + nullable: false, + }, + start: SourcePosition { + line: 3, + col: 12, + }, + end: SourcePosition { + line: 3, + col: 18, + }, + }, + default_value: None, + }, + start: SourcePosition { + line: 3, + col: 3, + }, + end: SourcePosition { + line: 3, + col: 18, + }, + }, + ], + start: SourcePosition { + line: 1, + col: 16, + }, + end: SourcePosition { + line: 4, + col: 1, + }, + }, + ), + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "item1", + ), + start: SourcePosition { + line: 5, + col: 3, + }, + end: SourcePosition { + line: 5, + col: 7, + }, + }, + arguments: Some( + Spanning { + item: [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "param1", + ), + start: SourcePosition { + line: 6, + col: 5, + }, + end: SourcePosition { + line: 6, + col: 10, + }, + }, + value: Spanning { + item: Variable( + Name( + "param1", + ), + ), + start: SourcePosition { + line: 6, + col: 13, + }, + end: SourcePosition { + line: 6, + col: 19, + }, + }, + }, + start: SourcePosition { + line: 6, + col: 5, + }, + end: SourcePosition { + line: 6, + col: 19, + }, + }, + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "param2", + ), + start: SourcePosition { + line: 7, + col: 5, + }, + end: SourcePosition { + line: 7, + col: 10, + }, + }, + value: Spanning { + item: Variable( + Name( + "param2", + ), + ), + start: SourcePosition { + line: 7, + col: 13, + }, + end: SourcePosition { + line: 7, + col: 19, + }, + }, + }, + start: SourcePosition { + line: 7, + col: 5, + }, + end: SourcePosition { + line: 7, + col: 19, + }, + }, + ], + start: SourcePosition { + line: 5, + col: 8, + }, + end: SourcePosition { + line: 8, + col: 3, + }, + }, + ), + directives: [], + selection_set: Some( + Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "id", + ), + start: SourcePosition { + line: 9, + col: 5, + }, + end: SourcePosition { + line: 9, + col: 6, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 9, + col: 5, + }, + end: SourcePosition { + line: 9, + col: 6, + }, + }, + Spanning { + item: InlineFragment( + InlineFragment { + type_condition: Some( + Spanning { + item: TypeCondition { + on: Spanning { + item: TypeName( + Name( + "Fragment1", + ), + ), + start: SourcePosition { + line: 10, + col: 12, + }, + end: SourcePosition { + line: 10, + col: 20, + }, + }, + }, + start: SourcePosition { + line: 10, + col: 9, + }, + end: SourcePosition { + line: 10, + col: 20, + }, + }, + ), + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "field3", + ), + start: SourcePosition { + line: 11, + col: 7, + }, + end: SourcePosition { + line: 11, + col: 12, + }, + }, + arguments: None, + directives: [], + selection_set: Some( + Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "field4", + ), + start: SourcePosition { + line: 12, + col: 9, + }, + end: SourcePosition { + line: 12, + col: 14, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 12, + col: 9, + }, + end: SourcePosition { + line: 12, + col: 14, + }, + }, + ], + }, + start: SourcePosition { + line: 11, + col: 14, + }, + end: SourcePosition { + line: 13, + col: 7, + }, + }, + ), + }, + ), + start: SourcePosition { + line: 11, + col: 7, + }, + end: SourcePosition { + line: 11, + col: 12, + }, + }, + ], + }, + start: SourcePosition { + line: 10, + col: 22, + }, + end: SourcePosition { + line: 14, + col: 5, + }, + }, + }, + ), + start: SourcePosition { + line: 10, + col: 5, + }, + end: SourcePosition { + line: 14, + col: 5, + }, + }, + ], + }, + start: SourcePosition { + line: 8, + col: 5, + }, + end: SourcePosition { + line: 15, + col: 3, + }, + }, + ), + }, + ), + start: SourcePosition { + line: 5, + col: 3, + }, + end: SourcePosition { + line: 5, + col: 7, + }, + }, + ], + }, + start: SourcePosition { + line: 4, + col: 3, + }, + end: SourcePosition { + line: 16, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 16, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/0039_variable_with_directives.graphql.2021 b/v3/lang-graphql/tests/query_testdata/ok/0039_variable_with_directives.graphql.2021 new file mode 100644 index 00000000000..d4ceb76a08c --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/0039_variable_with_directives.graphql.2021 @@ -0,0 +1,4 @@ +# Note @deprecated is only allowed in SDL AFAIU, but we'll allow it here +query getOutput($input: Int @deprecated $config: String = "Config" @tag(name: "team-customers")) { + animal +} diff --git a/v3/lang-graphql/tests/query_testdata/ok/1111_parses_variable_inline_values.graphql b/v3/lang-graphql/tests/query_testdata/ok/1111_parses_variable_inline_values.graphql new file mode 100644 index 00000000000..efe899e21a4 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/1111_parses_variable_inline_values.graphql @@ -0,0 +1 @@ +{ field(complex: { a: { b: [ $var ] } }) } diff --git a/v3/lang-graphql/tests/query_testdata/ok/1111_parses_variable_inline_values.txt b/v3/lang-graphql/tests/query_testdata/ok/1111_parses_variable_inline_values.txt new file mode 100644 index 00000000000..b82bd8ccc5a --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/1111_parses_variable_inline_values.txt @@ -0,0 +1,214 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: None, + variable_definitions: None, + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "field", + ), + start: SourcePosition { + line: 1, + col: 3, + }, + end: SourcePosition { + line: 1, + col: 7, + }, + }, + arguments: Some( + Spanning { + item: [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "complex", + ), + start: SourcePosition { + line: 1, + col: 9, + }, + end: SourcePosition { + line: 1, + col: 15, + }, + }, + value: Spanning { + item: Object( + [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "a", + ), + start: SourcePosition { + line: 1, + col: 20, + }, + end: SourcePosition { + line: 1, + col: 20, + }, + }, + value: Spanning { + item: Object( + [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "b", + ), + start: SourcePosition { + line: 1, + col: 25, + }, + end: SourcePosition { + line: 1, + col: 25, + }, + }, + value: Spanning { + item: List( + [ + Spanning { + item: Variable( + Name( + "var", + ), + ), + start: SourcePosition { + line: 1, + col: 30, + }, + end: SourcePosition { + line: 1, + col: 33, + }, + }, + ], + ), + start: SourcePosition { + line: 1, + col: 28, + }, + end: SourcePosition { + line: 1, + col: 35, + }, + }, + }, + start: SourcePosition { + line: 1, + col: 25, + }, + end: SourcePosition { + line: 1, + col: 35, + }, + }, + ], + ), + start: SourcePosition { + line: 1, + col: 23, + }, + end: SourcePosition { + line: 1, + col: 37, + }, + }, + }, + start: SourcePosition { + line: 1, + col: 20, + }, + end: SourcePosition { + line: 1, + col: 37, + }, + }, + ], + ), + start: SourcePosition { + line: 1, + col: 18, + }, + end: SourcePosition { + line: 1, + col: 39, + }, + }, + }, + start: SourcePosition { + line: 1, + col: 9, + }, + end: SourcePosition { + line: 1, + col: 39, + }, + }, + ], + start: SourcePosition { + line: 1, + col: 8, + }, + end: SourcePosition { + line: 1, + col: 40, + }, + }, + ), + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 1, + col: 3, + }, + end: SourcePosition { + line: 1, + col: 7, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 1, + col: 42, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 1, + col: 42, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/1112_parses_variable_definition_directives.graphql.2021 b/v3/lang-graphql/tests/query_testdata/ok/1112_parses_variable_definition_directives.graphql.2021 new file mode 100644 index 00000000000..c5c0fa63437 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/1112_parses_variable_definition_directives.graphql.2021 @@ -0,0 +1 @@ +query Foo($x: Boolean = false @bar) { field } diff --git a/v3/lang-graphql/tests/query_testdata/ok/1113_parses_multibyte_chars.graphql b/v3/lang-graphql/tests/query_testdata/ok/1113_parses_multibyte_chars.graphql new file mode 100644 index 00000000000..b65641353b9 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/1113_parses_multibyte_chars.graphql @@ -0,0 +1,2 @@ +# This comment has a \u0A0A multi-byte character. +{ field(arg: "Has a \u0A0A multi-byte character.") } diff --git a/v3/lang-graphql/tests/query_testdata/ok/1113_parses_multibyte_chars.txt b/v3/lang-graphql/tests/query_testdata/ok/1113_parses_multibyte_chars.txt new file mode 100644 index 00000000000..2f475a4d91e --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/1113_parses_multibyte_chars.txt @@ -0,0 +1,122 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: None, + variable_definitions: None, + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "field", + ), + start: SourcePosition { + line: 2, + col: 3, + }, + end: SourcePosition { + line: 2, + col: 7, + }, + }, + arguments: Some( + Spanning { + item: [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "arg", + ), + start: SourcePosition { + line: 2, + col: 9, + }, + end: SourcePosition { + line: 2, + col: 11, + }, + }, + value: Spanning { + item: SimpleValue( + String( + "Has a ਊ multi-byte character.", + ), + ), + start: SourcePosition { + line: 2, + col: 14, + }, + end: SourcePosition { + line: 2, + col: 49, + }, + }, + }, + start: SourcePosition { + line: 2, + col: 9, + }, + end: SourcePosition { + line: 2, + col: 49, + }, + }, + ], + start: SourcePosition { + line: 2, + col: 8, + }, + end: SourcePosition { + line: 2, + col: 50, + }, + }, + ), + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 2, + col: 3, + }, + end: SourcePosition { + line: 2, + col: 7, + }, + }, + ], + }, + start: SourcePosition { + line: 2, + col: 1, + }, + end: SourcePosition { + line: 2, + col: 52, + }, + }, + }, + ), + start: SourcePosition { + line: 2, + col: 1, + }, + end: SourcePosition { + line: 2, + col: 52, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/1114_parses_anonymous_mutation.graphql b/v3/lang-graphql/tests/query_testdata/ok/1114_parses_anonymous_mutation.graphql new file mode 100644 index 00000000000..9737e7c0aa7 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/1114_parses_anonymous_mutation.graphql @@ -0,0 +1,3 @@ + mutation { + mutationField + } diff --git a/v3/lang-graphql/tests/query_testdata/ok/1114_parses_anonymous_mutation.txt b/v3/lang-graphql/tests/query_testdata/ok/1114_parses_anonymous_mutation.txt new file mode 100644 index 00000000000..472877edb10 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/1114_parses_anonymous_mutation.txt @@ -0,0 +1,69 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Mutation, + name: None, + variable_definitions: None, + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "mutationField", + ), + start: SourcePosition { + line: 2, + col: 9, + }, + end: SourcePosition { + line: 2, + col: 21, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 2, + col: 9, + }, + end: SourcePosition { + line: 2, + col: 21, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 16, + }, + end: SourcePosition { + line: 3, + col: 7, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 7, + }, + end: SourcePosition { + line: 3, + col: 7, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/1115_parses_anonymous_subscription.graphql b/v3/lang-graphql/tests/query_testdata/ok/1115_parses_anonymous_subscription.graphql new file mode 100644 index 00000000000..052beeef7c9 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/1115_parses_anonymous_subscription.graphql @@ -0,0 +1,3 @@ + subscription { + subscriptionField + } diff --git a/v3/lang-graphql/tests/query_testdata/ok/1115_parses_anonymous_subscription.txt b/v3/lang-graphql/tests/query_testdata/ok/1115_parses_anonymous_subscription.txt new file mode 100644 index 00000000000..4a0136c2b9f --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/1115_parses_anonymous_subscription.txt @@ -0,0 +1,69 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Subscription, + name: None, + variable_definitions: None, + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "subscriptionField", + ), + start: SourcePosition { + line: 2, + col: 9, + }, + end: SourcePosition { + line: 2, + col: 25, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 2, + col: 9, + }, + end: SourcePosition { + line: 2, + col: 25, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 20, + }, + end: SourcePosition { + line: 3, + col: 7, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 7, + }, + end: SourcePosition { + line: 3, + col: 7, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/9011_escaped_char.graphql b/v3/lang-graphql/tests/query_testdata/ok/9011_escaped_char.graphql new file mode 100644 index 00000000000..f6b43381185 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/9011_escaped_char.graphql @@ -0,0 +1,6 @@ +query MyQuery { + Album(limit: 10, where: {Title: {_eq: "\""}}) { + Title + } +} + diff --git a/v3/lang-graphql/tests/query_testdata/ok/9011_escaped_char.txt b/v3/lang-graphql/tests/query_testdata/ok/9011_escaped_char.txt new file mode 100644 index 00000000000..0c7689cf8d4 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/9011_escaped_char.txt @@ -0,0 +1,300 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Query, + name: Some( + Spanning { + item: Name( + "MyQuery", + ), + start: SourcePosition { + line: 1, + col: 7, + }, + end: SourcePosition { + line: 1, + col: 13, + }, + }, + ), + variable_definitions: None, + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "Album", + ), + start: SourcePosition { + line: 2, + col: 3, + }, + end: SourcePosition { + line: 2, + col: 7, + }, + }, + arguments: Some( + Spanning { + item: [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "limit", + ), + start: SourcePosition { + line: 2, + col: 9, + }, + end: SourcePosition { + line: 2, + col: 13, + }, + }, + value: Spanning { + item: SimpleValue( + Integer( + 10, + ), + ), + start: SourcePosition { + line: 2, + col: 16, + }, + end: SourcePosition { + line: 2, + col: 17, + }, + }, + }, + start: SourcePosition { + line: 2, + col: 9, + }, + end: SourcePosition { + line: 2, + col: 17, + }, + }, + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "where", + ), + start: SourcePosition { + line: 2, + col: 20, + }, + end: SourcePosition { + line: 2, + col: 24, + }, + }, + value: Spanning { + item: Object( + [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "Title", + ), + start: SourcePosition { + line: 2, + col: 28, + }, + end: SourcePosition { + line: 2, + col: 32, + }, + }, + value: Spanning { + item: Object( + [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "_eq", + ), + start: SourcePosition { + line: 2, + col: 36, + }, + end: SourcePosition { + line: 2, + col: 38, + }, + }, + value: Spanning { + item: SimpleValue( + String( + "\"", + ), + ), + start: SourcePosition { + line: 2, + col: 41, + }, + end: SourcePosition { + line: 2, + col: 44, + }, + }, + }, + start: SourcePosition { + line: 2, + col: 36, + }, + end: SourcePosition { + line: 2, + col: 44, + }, + }, + ], + ), + start: SourcePosition { + line: 2, + col: 35, + }, + end: SourcePosition { + line: 2, + col: 45, + }, + }, + }, + start: SourcePosition { + line: 2, + col: 28, + }, + end: SourcePosition { + line: 2, + col: 45, + }, + }, + ], + ), + start: SourcePosition { + line: 2, + col: 27, + }, + end: SourcePosition { + line: 2, + col: 46, + }, + }, + }, + start: SourcePosition { + line: 2, + col: 20, + }, + end: SourcePosition { + line: 2, + col: 46, + }, + }, + ], + start: SourcePosition { + line: 2, + col: 8, + }, + end: SourcePosition { + line: 2, + col: 47, + }, + }, + ), + directives: [], + selection_set: Some( + Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "Title", + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 9, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 9, + }, + }, + ], + }, + start: SourcePosition { + line: 2, + col: 49, + }, + end: SourcePosition { + line: 4, + col: 3, + }, + }, + ), + }, + ), + start: SourcePosition { + line: 2, + col: 3, + }, + end: SourcePosition { + line: 2, + col: 7, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 15, + }, + end: SourcePosition { + line: 5, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 5, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/query_testdata/ok/9013_emoji_char_in_string_value.graphql b/v3/lang-graphql/tests/query_testdata/ok/9013_emoji_char_in_string_value.graphql new file mode 100644 index 00000000000..cf50d2253ad --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/9013_emoji_char_in_string_value.graphql @@ -0,0 +1,5 @@ +mutation UpdateStuff { + stuffUpdate(input: { + tags: "really great 👻 halloween" + }) { stuff { tags } } +} diff --git a/v3/lang-graphql/tests/query_testdata/ok/9013_emoji_char_in_string_value.txt b/v3/lang-graphql/tests/query_testdata/ok/9013_emoji_char_in_string_value.txt new file mode 100644 index 00000000000..3fea37a42c0 --- /dev/null +++ b/v3/lang-graphql/tests/query_testdata/ok/9013_emoji_char_in_string_value.txt @@ -0,0 +1,267 @@ +Ok( + ExecutableDocument { + items: [ + Spanning { + item: Operation( + OperationDefinition { + ty: Mutation, + name: Some( + Spanning { + item: Name( + "UpdateStuff", + ), + start: SourcePosition { + line: 1, + col: 10, + }, + end: SourcePosition { + line: 1, + col: 20, + }, + }, + ), + variable_definitions: None, + directives: [], + selection_set: Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "stuffUpdate", + ), + start: SourcePosition { + line: 2, + col: 3, + }, + end: SourcePosition { + line: 2, + col: 13, + }, + }, + arguments: Some( + Spanning { + item: [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "input", + ), + start: SourcePosition { + line: 2, + col: 15, + }, + end: SourcePosition { + line: 2, + col: 19, + }, + }, + value: Spanning { + item: Object( + [ + Spanning { + item: KeyValue { + key: Spanning { + item: Name( + "tags", + ), + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 8, + }, + }, + value: Spanning { + item: SimpleValue( + String( + "really great 👻 halloween", + ), + ), + start: SourcePosition { + line: 3, + col: 11, + }, + end: SourcePosition { + line: 3, + col: 36, + }, + }, + }, + start: SourcePosition { + line: 3, + col: 5, + }, + end: SourcePosition { + line: 3, + col: 36, + }, + }, + ], + ), + start: SourcePosition { + line: 2, + col: 22, + }, + end: SourcePosition { + line: 4, + col: 3, + }, + }, + }, + start: SourcePosition { + line: 2, + col: 15, + }, + end: SourcePosition { + line: 4, + col: 3, + }, + }, + ], + start: SourcePosition { + line: 2, + col: 14, + }, + end: SourcePosition { + line: 4, + col: 4, + }, + }, + ), + directives: [], + selection_set: Some( + Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "stuff", + ), + start: SourcePosition { + line: 4, + col: 8, + }, + end: SourcePosition { + line: 4, + col: 12, + }, + }, + arguments: None, + directives: [], + selection_set: Some( + Spanning { + item: SelectionSet { + items: [ + Spanning { + item: Field( + Field { + alias: None, + name: Spanning { + item: Name( + "tags", + ), + start: SourcePosition { + line: 4, + col: 16, + }, + end: SourcePosition { + line: 4, + col: 19, + }, + }, + arguments: None, + directives: [], + selection_set: None, + }, + ), + start: SourcePosition { + line: 4, + col: 16, + }, + end: SourcePosition { + line: 4, + col: 19, + }, + }, + ], + }, + start: SourcePosition { + line: 4, + col: 14, + }, + end: SourcePosition { + line: 4, + col: 21, + }, + }, + ), + }, + ), + start: SourcePosition { + line: 4, + col: 8, + }, + end: SourcePosition { + line: 4, + col: 12, + }, + }, + ], + }, + start: SourcePosition { + line: 4, + col: 6, + }, + end: SourcePosition { + line: 4, + col: 23, + }, + }, + ), + }, + ), + start: SourcePosition { + line: 2, + col: 3, + }, + end: SourcePosition { + line: 2, + col: 13, + }, + }, + ], + }, + start: SourcePosition { + line: 1, + col: 22, + }, + end: SourcePosition { + line: 5, + col: 1, + }, + }, + }, + ), + start: SourcePosition { + line: 1, + col: 1, + }, + end: SourcePosition { + line: 5, + col: 1, + }, + }, + ], + }, +) \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0001_directive_definition_missing_location.graphql b/v3/lang-graphql/tests/schema_testdata/err/0001_directive_definition_missing_location.graphql new file mode 100644 index 00000000000..edf9cf968f8 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0001_directive_definition_missing_location.graphql @@ -0,0 +1 @@ +directive @example on \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0002_enum_definition_with_missing_name.graphql b/v3/lang-graphql/tests/schema_testdata/err/0002_enum_definition_with_missing_name.graphql new file mode 100644 index 00000000000..8525d0b9232 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0002_enum_definition_with_missing_name.graphql @@ -0,0 +1,6 @@ +enum { + NORTH + EAST + SOUTH + WEST +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0003_enum_definition_with_missing_values.graphql b/v3/lang-graphql/tests/schema_testdata/err/0003_enum_definition_with_missing_values.graphql new file mode 100644 index 00000000000..1be2f30f21f --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0003_enum_definition_with_missing_values.graphql @@ -0,0 +1,2 @@ +enum Direction { +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0004_enum_definition_with_missing_curly.graphql b/v3/lang-graphql/tests/schema_testdata/err/0004_enum_definition_with_missing_curly.graphql new file mode 100644 index 00000000000..dc5c372f851 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0004_enum_definition_with_missing_curly.graphql @@ -0,0 +1 @@ +enum Direction { NORTH WEST \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0005_enum_extension_with_missing_name.graphql b/v3/lang-graphql/tests/schema_testdata/err/0005_enum_extension_with_missing_name.graphql new file mode 100644 index 00000000000..7ba334e9448 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0005_enum_extension_with_missing_name.graphql @@ -0,0 +1,4 @@ +extend enum { + NORTH + EAST +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0006_enum_extension_with_missing_requirements.graphql b/v3/lang-graphql/tests/schema_testdata/err/0006_enum_extension_with_missing_requirements.graphql new file mode 100644 index 00000000000..c617c9ed891 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0006_enum_extension_with_missing_requirements.graphql @@ -0,0 +1 @@ +extend enum Direction \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0010_input_definition_with_missing_name.graphql b/v3/lang-graphql/tests/schema_testdata/err/0010_input_definition_with_missing_name.graphql new file mode 100644 index 00000000000..997502631e6 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0010_input_definition_with_missing_name.graphql @@ -0,0 +1,4 @@ +input { + a: String + b: Int! +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0011_input_definition_with_missing_input_values.graphql b/v3/lang-graphql/tests/schema_testdata/err/0011_input_definition_with_missing_input_values.graphql new file mode 100644 index 00000000000..5347a19e5fa --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0011_input_definition_with_missing_input_values.graphql @@ -0,0 +1 @@ +input ExampleInputObject {} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0012_input_extension_with_missing_name.graphql b/v3/lang-graphql/tests/schema_testdata/err/0012_input_extension_with_missing_name.graphql new file mode 100644 index 00000000000..1770bc390ea --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0012_input_extension_with_missing_name.graphql @@ -0,0 +1,3 @@ +extend input { + a: String +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0013_input_extension_with_missing_requirements.graphql b/v3/lang-graphql/tests/schema_testdata/err/0013_input_extension_with_missing_requirements.graphql new file mode 100644 index 00000000000..7ea83228235 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0013_input_extension_with_missing_requirements.graphql @@ -0,0 +1 @@ +extend input ExampleInputObject \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0014_interface_extension_with_missing_name.graphql b/v3/lang-graphql/tests/schema_testdata/err/0014_interface_extension_with_missing_name.graphql new file mode 100644 index 00000000000..c15b3c74d0c --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0014_interface_extension_with_missing_name.graphql @@ -0,0 +1,3 @@ +extend interface { + value: Int +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0015_interface_extension_with_missing_requirements.graphql b/v3/lang-graphql/tests/schema_testdata/err/0015_interface_extension_with_missing_requirements.graphql new file mode 100644 index 00000000000..c98d47c3d3d --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0015_interface_extension_with_missing_requirements.graphql @@ -0,0 +1 @@ +extend interface ValuedEntity \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0016_object_type_extension_with_missing_name.graphql b/v3/lang-graphql/tests/schema_testdata/err/0016_object_type_extension_with_missing_name.graphql new file mode 100644 index 00000000000..2063097277e --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0016_object_type_extension_with_missing_name.graphql @@ -0,0 +1,5 @@ +extend type { + name: String + age: Int + picture: Url +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0017_object_type_extension_with_missing_requirements.graphql b/v3/lang-graphql/tests/schema_testdata/err/0017_object_type_extension_with_missing_requirements.graphql new file mode 100644 index 00000000000..82963fe23d2 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0017_object_type_extension_with_missing_requirements.graphql @@ -0,0 +1 @@ +extend type Person \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0018_scalar_definition_with_missing_name.graphql b/v3/lang-graphql/tests/schema_testdata/err/0018_scalar_definition_with_missing_name.graphql new file mode 100644 index 00000000000..928fa12e84a --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0018_scalar_definition_with_missing_name.graphql @@ -0,0 +1 @@ +scalar @deprecated \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0019_scalar_extension_with_missing_name.graphql b/v3/lang-graphql/tests/schema_testdata/err/0019_scalar_extension_with_missing_name.graphql new file mode 100644 index 00000000000..f1520bc043f --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0019_scalar_extension_with_missing_name.graphql @@ -0,0 +1 @@ +extend scalar @deprecated \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0020_union_definition_with_missing_name.graphql b/v3/lang-graphql/tests/schema_testdata/err/0020_union_definition_with_missing_name.graphql new file mode 100644 index 00000000000..eda60235697 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0020_union_definition_with_missing_name.graphql @@ -0,0 +1 @@ +union = Photo | Person \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0021_union_definition_with_missing_union_members.graphql b/v3/lang-graphql/tests/schema_testdata/err/0021_union_definition_with_missing_union_members.graphql new file mode 100644 index 00000000000..8d8135820fe --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0021_union_definition_with_missing_union_members.graphql @@ -0,0 +1 @@ +union = \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0022_union_extension_with_missing_name.graphql b/v3/lang-graphql/tests/schema_testdata/err/0022_union_extension_with_missing_name.graphql new file mode 100644 index 00000000000..c1bb85969bd --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0022_union_extension_with_missing_name.graphql @@ -0,0 +1 @@ +extend union = Photo | Person \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0023_union_extension_with_missing_requirements.graphql b/v3/lang-graphql/tests/schema_testdata/err/0023_union_extension_with_missing_requirements.graphql new file mode 100644 index 00000000000..ae7693ffac2 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0023_union_extension_with_missing_requirements.graphql @@ -0,0 +1 @@ +extend union SearchResult \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0026_invalid_definition_squished_between_two_valid_definitions.graphql b/v3/lang-graphql/tests/schema_testdata/err/0026_invalid_definition_squished_between_two_valid_definitions.graphql new file mode 100644 index 00000000000..548afaf51c7 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0026_invalid_definition_squished_between_two_valid_definitions.graphql @@ -0,0 +1,16 @@ +enum Direction @example { + """ + description + """ + NORTH + EAST + SOUTH + WEST +} + +uasdf21230jkdw + +{ + pet + faveSnack +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0028_invalid_type_system_extension_followed_by_valid.graphql b/v3/lang-graphql/tests/schema_testdata/err/0028_invalid_type_system_extension_followed_by_valid.graphql new file mode 100644 index 00000000000..c1ed29d66fe --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0028_invalid_type_system_extension_followed_by_valid.graphql @@ -0,0 +1,5 @@ +extend Cat + +extend interface NamedEntity { + name: String +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0032_input_value_with_erronous_string_value.graphql b/v3/lang-graphql/tests/schema_testdata/err/0032_input_value_with_erronous_string_value.graphql new file mode 100644 index 00000000000..f963502b95c --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0032_input_value_with_erronous_string_value.graphql @@ -0,0 +1,4 @@ +type Person { + name: String + picture(reference: "\a reference image"): Url +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0033_directive_with_erronous_string_value.graphql b/v3/lang-graphql/tests/schema_testdata/err/0033_directive_with_erronous_string_value.graphql new file mode 100644 index 00000000000..942cf4b8e13 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0033_directive_with_erronous_string_value.graphql @@ -0,0 +1,5 @@ +directive @delegateField(name: String!) repeatable on OBJECT | INTERFACE + +type Book @delegateField(name: "\ errronous string \""){ + id: ID! +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0034_unterminated_string_value_in_list.graphql b/v3/lang-graphql/tests/schema_testdata/err/0034_unterminated_string_value_in_list.graphql new file mode 100644 index 00000000000..3abb1c4e86a --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0034_unterminated_string_value_in_list.graphql @@ -0,0 +1,12 @@ +extend schema + @link(url: "https://specs.apollo.dev/federation/v2.0", + import: ["@key", "@external]) + + +type Vehicle @key(fields: "id") { + id: ID!, + type: String, + modelCode: String, + brandName: String, + launchDate: String +} diff --git a/v3/lang-graphql/tests/schema_testdata/err/0036_unterminated_string_in_default_value.graphql b/v3/lang-graphql/tests/schema_testdata/err/0036_unterminated_string_in_default_value.graphql new file mode 100644 index 00000000000..d50eb37ab36 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0036_unterminated_string_in_default_value.graphql @@ -0,0 +1,4 @@ +type Person { + name: String + picture(url: String = "https://spec.graphql.org/October2021/#DefaultValue): Url +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0042_document_with_incorrect_token.graphql b/v3/lang-graphql/tests/schema_testdata/err/0042_document_with_incorrect_token.graphql new file mode 100644 index 00000000000..60f48de2915 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0042_document_with_incorrect_token.graphql @@ -0,0 +1,13 @@ +@ +# comment +{ + pet + faveSnack +} + +# comment +} + +type Query { + name: String +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/err/0043_type_with_trailing_garbage.graphql b/v3/lang-graphql/tests/schema_testdata/err/0043_type_with_trailing_garbage.graphql new file mode 100644 index 00000000000..3874d614525 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0043_type_with_trailing_garbage.graphql @@ -0,0 +1,6 @@ +type Person { + id: ID! + appearedIn: [Film]s + name: String + directed: [Film] +} diff --git a/v3/lang-graphql/tests/schema_testdata/err/0044_list_type_with_no_type.graphql b/v3/lang-graphql/tests/schema_testdata/err/0044_list_type_with_no_type.graphql new file mode 100644 index 00000000000..ceb95440353 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0044_list_type_with_no_type.graphql @@ -0,0 +1,4 @@ +type List { + field: [] @coolDirective + deepError: [[[Item Type]]] +} diff --git a/v3/lang-graphql/tests/schema_testdata/err/0045_ignored_token_spans.graphql b/v3/lang-graphql/tests/schema_testdata/err/0045_ignored_token_spans.graphql new file mode 100644 index 00000000000..03ac94f6269 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0045_ignored_token_spans.graphql @@ -0,0 +1,9 @@ +cats +# https://github.com/apollographql/apollo-rs/issues/325 + +interface X {} + +cats +type Query { + name: String +} diff --git a/v3/lang-graphql/tests/schema_testdata/err/0048_unbalanced_list_type_1.graphql b/v3/lang-graphql/tests/schema_testdata/err/0048_unbalanced_list_type_1.graphql new file mode 100644 index 00000000000..34f99c81884 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0048_unbalanced_list_type_1.graphql @@ -0,0 +1,3 @@ +type Query { + unbalanced: [[Int]]] +} diff --git a/v3/lang-graphql/tests/schema_testdata/err/0049_unbalanced_list_type_2.graphql b/v3/lang-graphql/tests/schema_testdata/err/0049_unbalanced_list_type_2.graphql new file mode 100644 index 00000000000..b677251bf3a --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0049_unbalanced_list_type_2.graphql @@ -0,0 +1,3 @@ +type Query { + unbalanced: [[[Int]] +} diff --git a/v3/lang-graphql/tests/schema_testdata/err/0050_invalid_implements_list.graphql b/v3/lang-graphql/tests/schema_testdata/err/0050_invalid_implements_list.graphql new file mode 100644 index 00000000000..3a43bfd0a2b --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0050_invalid_implements_list.graphql @@ -0,0 +1,5 @@ +type Obj implements A & { field: Int } + +type Obj implements A B { field: Int } + +type Obj implements A && B { field: Int } diff --git a/v3/lang-graphql/tests/schema_testdata/err/0051_union_with_invalid_members_list.graphql b/v3/lang-graphql/tests/schema_testdata/err/0051_union_with_invalid_members_list.graphql new file mode 100644 index 00000000000..21de319ace7 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/err/0051_union_with_invalid_members_list.graphql @@ -0,0 +1,8 @@ +"Missing separator" +union SearchResult = Photo Person + +"Double separator" +union SearchResult2 = Photo || Person + +"Dangling separator" +union SearchResult3 = | Photo | Person | diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0007_directive_definition.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0007_directive_definition.graphql new file mode 100644 index 00000000000..2b9b2fd6fb8 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0007_directive_definition.graphql @@ -0,0 +1 @@ +directive @example on FIELD \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0008_directive_definition_with_arguments.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0008_directive_definition_with_arguments.graphql new file mode 100644 index 00000000000..6f0ecdbf356 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0008_directive_definition_with_arguments.graphql @@ -0,0 +1 @@ +directive @example(isTreat: Boolean, treatKind: String) on FIELD | MUTATION \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0009_directive_definition_repeatable.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0009_directive_definition_repeatable.graphql new file mode 100644 index 00000000000..ee0fbacf80b --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0009_directive_definition_repeatable.graphql @@ -0,0 +1 @@ +directive @example(isTreat: Boolean, treatKind: String) repeatable on FIELD | MUTATION \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0010_enum_type_definition.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0010_enum_type_definition.graphql new file mode 100644 index 00000000000..460626135bf --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0010_enum_type_definition.graphql @@ -0,0 +1,9 @@ +enum Direction @example { + """ + description + """ + NORTH + EAST + SOUTH + WEST +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0011_enum_type_extension.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0011_enum_type_extension.graphql new file mode 100644 index 00000000000..e9088a18ef7 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0011_enum_type_extension.graphql @@ -0,0 +1,4 @@ +extend enum Direction @example { + SOUTH + WEST +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0014_input_definition.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0014_input_definition.graphql new file mode 100644 index 00000000000..8f2b1b2828a --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0014_input_definition.graphql @@ -0,0 +1,4 @@ +input ExampleInputObject { + a: String + b: Int! +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0015_input_extension.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0015_input_extension.graphql new file mode 100644 index 00000000000..4e91e967404 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0015_input_extension.graphql @@ -0,0 +1,3 @@ +extend input ExampleInputObject @skip { + a: String +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0016_interface_definition.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0016_interface_definition.graphql new file mode 100644 index 00000000000..e2e9e56efab --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0016_interface_definition.graphql @@ -0,0 +1,3 @@ +interface ValuedEntity { + value: Int +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0017_interface_extension.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0017_interface_extension.graphql new file mode 100644 index 00000000000..7683ac88d3b --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0017_interface_extension.graphql @@ -0,0 +1,3 @@ +extend interface ValuedEntity @skip { + value: Int +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0018_object_type_definition.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0018_object_type_definition.graphql new file mode 100644 index 00000000000..4f60a7e3fcd --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0018_object_type_definition.graphql @@ -0,0 +1,9 @@ +"description of type" +type Person implements Human { + """ + description of field + """ + name: String + age: Int + picture: Url +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0019_object_type_extension.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0019_object_type_extension.graphql new file mode 100644 index 00000000000..208aa798a92 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0019_object_type_extension.graphql @@ -0,0 +1,5 @@ +extend type Person implements Human @deprecated { + name: String + age: Int + picture: Url +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0023_scalar_definition.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0023_scalar_definition.graphql new file mode 100644 index 00000000000..d3e3722fe02 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0023_scalar_definition.graphql @@ -0,0 +1 @@ +scalar Time @deprecated \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0024_scalar_extension.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0024_scalar_extension.graphql new file mode 100644 index 00000000000..835902abd3b --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0024_scalar_extension.graphql @@ -0,0 +1 @@ +extend scalar Time @deprecated \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0025_schema_definition.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0025_schema_definition.graphql new file mode 100644 index 00000000000..66c31eb8aa0 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0025_schema_definition.graphql @@ -0,0 +1,5 @@ +schema { + query: MyQueryRootType + mutation: MyMutationRootType, + subscription: MySubscriptionRootType +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0026_schema_extension.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0026_schema_extension.graphql new file mode 100644 index 00000000000..803b621b35d --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0026_schema_extension.graphql @@ -0,0 +1,3 @@ +extend schema @skip @example { + query: MyExtendedQueryType +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0027_union_type_definition.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0027_union_type_definition.graphql new file mode 100644 index 00000000000..40f9173bfde --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0027_union_type_definition.graphql @@ -0,0 +1,5 @@ +union SearchResult = Photo | Person + +union MultiLine = + | Photo + | Person diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0028_union_type_definition_followed_by_object_definition.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0028_union_type_definition_followed_by_object_definition.graphql new file mode 100644 index 00000000000..2f399163eb5 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0028_union_type_definition_followed_by_object_definition.graphql @@ -0,0 +1,5 @@ +union SearchResult = Photo | Person + +type Error { + code: Int +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0029_union_type_extension.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0029_union_type_extension.graphql new file mode 100644 index 00000000000..b120b23b821 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0029_union_type_extension.graphql @@ -0,0 +1 @@ +extend union SearchResult @deprecated = Photo | Person \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0032_supergraph.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0032_supergraph.graphql new file mode 100644 index 00000000000..7e425acd441 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0032_supergraph.graphql @@ -0,0 +1,266 @@ +schema +@core(feature: "https://specs.apollo.dev/core/v0.1"), +@core(feature: "https://specs.apollo.dev/join/v0.1") +{ + query: Query + mutation: Mutation +} + +directive @core(feature: String!) repeatable on SCHEMA +directive @join__field(graph: join__Graph, requires: join__FieldSet, provides: join__FieldSet) on FIELD_DEFINITION +directive @join__type(graph: join__Graph!, key: join__FieldSet) repeatable on OBJECT | INTERFACE +directive @join__owner(graph: join__Graph!) on OBJECT | INTERFACE +directive @join__graph(name: String!, url: String!) on ENUM_VALUE +directive @stream on FIELD +directive @transform(from: String!) on FIELD + +union AccountType = PasswordAccount | SMSAccount + +type Amazon { + referrer: String +} + +union Body = Image | Text + +type Book implements Product +@join__owner(graph: BOOKS) +@join__type(graph: BOOKS, key: "isbn") +@join__type(graph: INVENTORY, key: "isbn") +@join__type(graph: PRODUCT, key: "isbn") +@join__type(graph: REVIEWS, key: "isbn") +{ + isbn: String! @join__field(graph: BOOKS) + title: String @join__field(graph: BOOKS) + year: Int @join__field(graph: BOOKS) + similarBooks: [Book]! @join__field(graph: BOOKS) + metadata: [MetadataOrError] @join__field(graph: BOOKS) + inStock: Boolean @join__field(graph: INVENTORY) + isCheckedOut: Boolean @join__field(graph: INVENTORY) + upc: String! @join__field(graph: PRODUCT) + sku: String! @join__field(graph: PRODUCT) + name(delimeter: String = " "): String @join__field(graph: PRODUCT, requires: "title year") + price: String @join__field(graph: PRODUCT) + details: ProductDetailsBook @join__field(graph: PRODUCT) + reviews: [Review] @join__field(graph: REVIEWS) + relatedReviews: [Review!]! @join__field(graph: REVIEWS, requires: "similarBooks{isbn}") +} + +union Brand = Ikea | Amazon + +type Car implements Vehicle +@join__owner(graph: PRODUCT) +@join__type(graph: PRODUCT, key: "id") +@join__type(graph: REVIEWS, key: "id") +{ + id: String! @join__field(graph: PRODUCT) + description: String @join__field(graph: PRODUCT) + price: String @join__field(graph: PRODUCT) + retailPrice: String @join__field(graph: REVIEWS, requires: "price") +} + +type Error { + code: Int + message: String +} + +type Furniture implements Product +@join__owner(graph: PRODUCT) +@join__type(graph: PRODUCT, key: "upc") +@join__type(graph: PRODUCT, key: "sku") +@join__type(graph: INVENTORY, key: "sku") +@join__type(graph: REVIEWS, key: "upc") +{ + upc: String! @join__field(graph: PRODUCT) + sku: String! @join__field(graph: PRODUCT) + name: String @join__field(graph: PRODUCT) + price: String @join__field(graph: PRODUCT) + brand: Brand @join__field(graph: PRODUCT) + metadata: [MetadataOrError] @join__field(graph: PRODUCT) + details: ProductDetailsFurniture @join__field(graph: PRODUCT) + inStock: Boolean @join__field(graph: INVENTORY) + isHeavy: Boolean @join__field(graph: INVENTORY) + reviews: [Review] @join__field(graph: REVIEWS) +} + +type Ikea { + asile: Int +} + +type Image implements NamedObject { + name: String! + attributes: ImageAttributes! +} + +type ImageAttributes { + url: String! +} + +scalar join__FieldSet + +enum join__Graph { +ACCOUNTS @join__graph(name: "accounts" url: "") +BOOKS @join__graph(name: "books" url: "") +DOCUMENTS @join__graph(name: "documents" url: "") +INVENTORY @join__graph(name: "inventory" url: "") +PRODUCT @join__graph(name: "product" url: "") +REVIEWS @join__graph(name: "reviews" url: "") +} + +type KeyValue { + key: String! + value: String! +} + +type Library +@join__owner(graph: BOOKS) +@join__type(graph: BOOKS, key: "id") +@join__type(graph: ACCOUNTS, key: "id") +{ + id: ID! @join__field(graph: BOOKS) + name: String @join__field(graph: BOOKS) + userAccount(id: ID! = 1): User @join__field(graph: ACCOUNTS, requires: "name") +} + +union MetadataOrError = KeyValue | Error + +type Mutation { + login(username: String!, password: String!): User @join__field(graph: ACCOUNTS) + reviewProduct(upc: String!, body: String!): Product @join__field(graph: REVIEWS) + updateReview(review: UpdateReviewInput!): Review @join__field(graph: REVIEWS) + deleteReview(id: ID!): Boolean @join__field(graph: REVIEWS) +} + +type Name { + first: String + last: String +} + +interface NamedObject { + name: String! +} + +type PasswordAccount +@join__owner(graph: ACCOUNTS) +@join__type(graph: ACCOUNTS, key: "email") +{ + email: String! @join__field(graph: ACCOUNTS) +} + +interface Product { + upc: String! + sku: String! + name: String + price: String + details: ProductDetails + inStock: Boolean + reviews: [Review] +} + +interface ProductDetails { + country: String +} + +type ProductDetailsBook implements ProductDetails { + country: String + pages: Int +} + +type ProductDetailsFurniture implements ProductDetails { + country: String + color: String +} + +type Query { + user(id: ID!): User @join__field(graph: ACCOUNTS) + me: User @join__field(graph: ACCOUNTS) + book(isbn: String!): Book @join__field(graph: BOOKS) + books: [Book] @join__field(graph: BOOKS) + library(id: ID!): Library @join__field(graph: BOOKS) + body: Body! @join__field(graph: DOCUMENTS) + product(upc: String!): Product @join__field(graph: PRODUCT) + vehicle(id: String!): Vehicle @join__field(graph: PRODUCT) + topProducts(first: Int = 5): [Product] @join__field(graph: PRODUCT) + topCars(first: Int = 5): [Car] @join__field(graph: PRODUCT) + topReviews(first: Int = 5): [Review] @join__field(graph: REVIEWS) +} + +type Review +@join__owner(graph: REVIEWS) +@join__type(graph: REVIEWS, key: "id") +{ + id: ID! @join__field(graph: REVIEWS) + body(format: Boolean = false): String @join__field(graph: REVIEWS) + author: User @join__field(graph: REVIEWS, provides: "username") + product: Product @join__field(graph: REVIEWS) + metadata: [MetadataOrError] @join__field(graph: REVIEWS) +} + +type SMSAccount +@join__owner(graph: ACCOUNTS) +@join__type(graph: ACCOUNTS, key: "number") +{ + number: String @join__field(graph: ACCOUNTS) +} + +type Text implements NamedObject { + name: String! + attributes: TextAttributes! +} + +type TextAttributes { + bold: Boolean + text: String +} + +union Thing = Car | Ikea + +input UpdateReviewInput { + id: ID! + body: String +} + +type User +@join__owner(graph: ACCOUNTS) +@join__type(graph: ACCOUNTS, key: "id") +@join__type(graph: ACCOUNTS, key: "username name{first last}") +@join__type(graph: INVENTORY, key: "id") +@join__type(graph: PRODUCT, key: "id") +@join__type(graph: REVIEWS, key: "id") +{ + id: ID! @join__field(graph: ACCOUNTS) + name: Name @join__field(graph: ACCOUNTS) + username: String @join__field(graph: ACCOUNTS) + birthDate(locale: String): String @join__field(graph: ACCOUNTS) + account: AccountType @join__field(graph: ACCOUNTS) + metadata: [UserMetadata] @join__field(graph: ACCOUNTS) + goodDescription: Boolean @join__field(graph: INVENTORY, requires: "metadata{description}") + vehicle: Vehicle @join__field(graph: PRODUCT) + thing: Thing @join__field(graph: PRODUCT) + reviews: [Review] @join__field(graph: REVIEWS) + numberOfReviews: Int! @join__field(graph: REVIEWS) + goodAddress: Boolean @join__field(graph: REVIEWS, requires: "metadata{address}") +} + +type UserMetadata { + name: String + address: String + description: String +} + +type Van implements Vehicle +@join__owner(graph: PRODUCT) +@join__type(graph: PRODUCT, key: "id") +@join__type(graph: REVIEWS, key: "id") +{ + id: String! @join__field(graph: PRODUCT) + description: String @join__field(graph: PRODUCT) + price: String @join__field(graph: PRODUCT) + retailPrice: String @join__field(graph: REVIEWS, requires: "price") +} + +interface Vehicle { + id: String! + description: String + price: String + retailPrice: String +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0033_directive_on_argument_definition.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0033_directive_on_argument_definition.graphql new file mode 100644 index 00000000000..0880e7c4509 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0033_directive_on_argument_definition.graphql @@ -0,0 +1,3 @@ +type Mutation { + login(userId: String @deprecated(reason: "Use username instead")): User +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0038_wrapped_named_types.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0038_wrapped_named_types.graphql new file mode 100644 index 00000000000..96e2bace8aa --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0038_wrapped_named_types.graphql @@ -0,0 +1,15 @@ +type ObjectDef { + a: String + b: Int! + c: [Int!]! + d: [[[[[Int]]]]] + d: [[[[[Int!]!]!]!]!]! +} + +type ObjectDefTwo { + a: String, + b: Int!, + c: [Int!]!, + d: [[[[[Int]]]]], + d: [[[[[Int!]!]!]!]!]!, +} \ No newline at end of file diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0040_type_token_order.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0040_type_token_order.graphql new file mode 100644 index 00000000000..6560fc29814 --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0040_type_token_order.graphql @@ -0,0 +1,8 @@ +type Object { + #(apparently you can stick a comma in there?? please dont do it!) + field : [Int ,!] # comment + _other: +String,,, , +#garbage + realField: ID! +} diff --git a/v3/lang-graphql/tests/schema_testdata/ok/0041_implements_list.graphql b/v3/lang-graphql/tests/schema_testdata/ok/0041_implements_list.graphql new file mode 100644 index 00000000000..f9c66ad81cc --- /dev/null +++ b/v3/lang-graphql/tests/schema_testdata/ok/0041_implements_list.graphql @@ -0,0 +1,12 @@ +"Just one interface" +type One implements A { field: Int! } + +"Several interfaces" +type Two implements A & B & C { field: Int! } + +"&-prefixed" +type Three implements + & A + & B + & C +{ field: Int! }