diff --git a/src/parser/implements/ddl/database.rs b/src/parser/implements/ddl/database.rs index a0966320..52a15cf5 100644 --- a/src/parser/implements/ddl/database.rs +++ b/src/parser/implements/ddl/database.rs @@ -33,7 +33,9 @@ impl Parser { } _ => { return Err(ParsingError::wrap( - "not supported command. possible commands: (create database)", + format!( + "not supported command. possible commands: (create database): {current_token:?}", + ) )); } } @@ -74,9 +76,9 @@ impl Parser { query_builder = query_builder.set_name(identifier); } _ => { - return Err(ParsingError::wrap( - "not supported command. possible commands: (create database)", - )); + return Err(ParsingError::wrap(format!( + "not supported command. possible commands: (drop database): {current_token:?}", + ))); } } diff --git a/src/parser/implements/ddl/table.rs b/src/parser/implements/ddl/table.rs index effaea70..8f007582 100644 --- a/src/parser/implements/ddl/table.rs +++ b/src/parser/implements/ddl/table.rs @@ -56,7 +56,6 @@ impl Parser { match current_token { Token::RightParentheses => { - self.unget_next_token(current_token); break; } _ => { @@ -67,20 +66,6 @@ impl Parser { } } - // 닫는 괄호 체크 - if !self.has_next_token() { - return Err(ParsingError::wrap("E1209 need more tokens")); - } - - let current_token = self.get_next_token(); - - if Token::RightParentheses != current_token { - return Err(ParsingError::wrap(format!( - "E1210 expected ')'. but your input word is '{:?}'", - current_token - ))); - } - if !self.has_next_token() { return Ok(query_builder.build()); } diff --git a/src/parser/test/alter_database.rs b/src/parser/test/alter_database.rs index 816b2de6..f1a676b6 100644 --- a/src/parser/test/alter_database.rs +++ b/src/parser/test/alter_database.rs @@ -2,46 +2,137 @@ use crate::ast::ddl::alter_database::{ AlterDatabaseAction, AlterDatabaseQuery, AlterDatabaseRenameTo, }; -use crate::parser::context::ParserContext; +use crate::ast::SQLStatement; +use crate::lexer::tokens::Token; use crate::parser::predule::Parser; #[test] -pub fn alter_database_1() { - let text = r#" - ALTER DATABASE foo RENAME TO bar; - "# - .to_owned(); +fn test_handle_alter_database_query() { + struct TestCase { + name: String, + input: Vec, + expected: SQLStatement, + want_error: bool, + } - let mut parser = Parser::with_string(text).unwrap(); + let test_cases = vec![ + TestCase { + name: "ALTER DATABASE foo RENAME TO bar;".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::To, + Token::Identifier("bar".to_owned()), + Token::SemiColon, + ], + expected: AlterDatabaseQuery::builder() + .set_name("foo".to_owned()) + .set_action(AlterDatabaseAction::RenameTo(AlterDatabaseRenameTo { + name: "bar".into(), + })) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "ALTER DATABASE foo RENAME TO bar".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::To, + Token::Identifier("bar".to_owned()), + ], + expected: AlterDatabaseQuery::builder() + .set_name("foo".to_owned()) + .set_action(AlterDatabaseAction::RenameTo(AlterDatabaseRenameTo { + name: "bar".into(), + })) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "ALTER DATABASE foo".into(), + input: vec![Token::Identifier("foo".to_owned())], + expected: AlterDatabaseQuery::builder() + .set_name("foo".to_owned()) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "오류: 빈 토큰".into(), + input: vec![], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER DATABASE DELETE".into(), + input: vec![Token::Delete], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER DATABASE foo RENAME".into(), + input: vec![Token::Identifier("foo".to_owned()), Token::Rename], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER DATABASE foo RENAME CREATE".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::Create, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER DATABASE foo RENAME TO".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::To, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER DATABASE foo RENAME TO ALTER".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::To, + Token::Alter, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER DATABASE foo DELETE".into(), + input: vec![Token::Identifier("foo".to_owned()), Token::Delete], + expected: Default::default(), + want_error: true, + }, + ]; - let expected = AlterDatabaseQuery::builder() - .set_name("foo".to_owned()) - .set_action(AlterDatabaseAction::RenameTo(AlterDatabaseRenameTo { - name: "bar".into(), - })) - .build(); + for t in test_cases { + let mut parser = Parser::new(t.input); - assert_eq!( - parser.parse(ParserContext::default()).unwrap(), - vec![expected], - ); -} - -#[test] -pub fn alter_database_2() { - let text = r#" - ALTER DATABASE foo; - "# - .to_owned(); - - let mut parser = Parser::with_string(text).unwrap(); + let got = parser.handle_alter_database_query(); - let expected = AlterDatabaseQuery::builder() - .set_name("foo".to_owned()) - .build(); + assert_eq!( + got.is_err(), + t.want_error, + "{}: want_error: {}, error: {:?}", + t.name, + t.want_error, + got.err() + ); - assert_eq!( - parser.parse(ParserContext::default()).unwrap(), - vec![expected], - ); + if let Ok(statements) = got { + assert_eq!(statements, t.expected.into(), "TC: {}", t.name); + } + } } diff --git a/src/parser/test/create_database.rs b/src/parser/test/create_database.rs index f6da89bd..8a610a94 100644 --- a/src/parser/test/create_database.rs +++ b/src/parser/test/create_database.rs @@ -1,44 +1,100 @@ #![cfg(test)] use crate::ast::ddl::create_database::CreateDatabaseQuery; -use crate::parser::context::ParserContext; +use crate::ast::SQLStatement; +use crate::lexer::tokens::Token; use crate::parser::predule::Parser; #[test] -pub fn create_database_1() { - let text = r#" - CREATE DATABASE IF Not exists test_db; - "# - .to_owned(); +fn test_handle_create_database_query() { + struct TestCase { + name: String, + input: Vec, + expected: SQLStatement, + want_error: bool, + } - let mut parser = Parser::with_string(text).unwrap(); + let test_cases = vec![ + TestCase { + name: "CREATE DATABASE test_db;".into(), + input: vec![Token::Identifier("test_db".to_owned()), Token::SemiColon], + expected: CreateDatabaseQuery::builder() + .set_name("test_db".to_owned()) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "CREATE DATABASE test_db".into(), + input: vec![Token::Identifier("test_db".to_owned())], + expected: CreateDatabaseQuery::builder() + .set_name("test_db".to_owned()) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "CREATE DATABASE IF NOT EXISTS test_db;".into(), + input: vec![ + Token::If, + Token::Not, + Token::Exists, + Token::Identifier("test_db".to_owned()), + Token::SemiColon, + ], + expected: CreateDatabaseQuery::builder() + .set_name("test_db".to_owned()) + .set_if_not_exists(true) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "오류: 빈 토큰".into(), + input: vec![], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: CREATE DATABASE IF NOT EXISTS".into(), + input: vec![Token::If, Token::Not, Token::Exists], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "CREATE DATABASE IF NOT EXISTS DELETE;".into(), + input: vec![ + Token::If, + Token::Not, + Token::Exists, + Token::Delete, + Token::SemiColon, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "CREATE DATABASE test_db DELETE".into(), + input: vec![Token::Identifier("test_db".to_owned()), Token::Delete], + expected: Default::default(), + want_error: true, + }, + ]; - let expected = CreateDatabaseQuery::builder() - .set_name("test_db".to_owned()) - .set_if_not_exists(true) - .build(); + for t in test_cases { + let mut parser = Parser::new(t.input); - assert_eq!( - parser.parse(ParserContext::default()).unwrap(), - vec![expected], - ); -} - -#[test] -pub fn create_database_2() { - let text = r#" - CREATE DATABASE test_db; - "# - .to_owned(); - - let mut parser = Parser::with_string(text).unwrap(); + let got = parser.handle_create_database_query(); - let expected = CreateDatabaseQuery::builder() - .set_name("test_db".to_owned()) - .set_if_not_exists(false) - .build(); + assert_eq!( + got.is_err(), + t.want_error, + "TC: {} Error: {:?}", + t.name, + got.err() + ); - assert_eq!( - parser.parse(ParserContext::default()).unwrap(), - vec![expected], - ); + if let Ok(alias) = got { + assert_eq!(alias, t.expected, "TC: {}", t.name); + } + } } diff --git a/src/parser/test/ddl.rs b/src/parser/test/ddl.rs new file mode 100644 index 00000000..d690be5c --- /dev/null +++ b/src/parser/test/ddl.rs @@ -0,0 +1,801 @@ +#![cfg(test)] + +use crate::{ + ast::{ + ddl::{ + alter_database::{AlterDatabaseAction, AlterDatabaseQuery, AlterDatabaseRenameTo}, + alter_table::{AlterTableAction, AlterTableQuery, AlterTableRenameColumn}, + create_database::CreateDatabaseQuery, + create_table::CreateTableQuery, + drop_database::DropDatabaseQuery, + drop_table::DropTableQuery, + }, + types::{Column, DataType, TableName}, + SQLStatement, + }, + lexer::tokens::Token, + parser::parser::Parser, +}; + +#[test] +fn test_handle_create_query() { + struct TestCase { + name: String, + input: Vec, + expected: SQLStatement, + want_error: bool, + } + + let test_cases = vec![ + TestCase { + name: "CREATE DATABASE foo;".into(), + input: vec![ + Token::Database, + Token::Identifier("foo".to_owned()), + Token::SemiColon, + ], + expected: CreateDatabaseQuery::builder() + .set_name("foo".to_owned()) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "CREATE TABLE foo(id INT PRIMARY KEY)".into(), + input: vec![ + Token::Table, + Token::Identifier("foo".to_owned()), + Token::LeftParentheses, + Token::Identifier("id".to_owned()), + Token::Identifier("INT".to_owned()), + Token::Primary, + Token::Key, + Token::RightParentheses, + ], + expected: CreateTableQuery::builder() + .set_table(TableName::new(None, "foo".to_owned())) + .add_column( + Column::builder() + .set_name("id".to_owned()) + .set_data_type(DataType::Int) + .set_primary_key(true) + .build(), + ) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "오류: CREATE UPDATE".into(), + input: vec![Token::Update], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: 빈 토큰".into(), + input: vec![], + expected: Default::default(), + want_error: true, + }, + ]; + + for t in test_cases { + let mut parser = Parser::new(t.input); + let got = parser.handle_create_query(Default::default()); + + assert_eq!( + got.is_err(), + t.want_error, + "{}: want_error: {}, error: {:?}", + t.name, + t.want_error, + got.err() + ); + + if let Ok(statements) = got { + assert_eq!(statements, t.expected.into(), "TC: {}", t.name); + } + } +} + +#[test] +fn test_handle_alter_query() { + struct TestCase { + name: String, + input: Vec, + expected: SQLStatement, + want_error: bool, + } + + let test_cases = vec![ + TestCase { + name: "ALTER DATABASE foo RENAME TO bar".into(), + input: vec![ + Token::Database, + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::To, + Token::Identifier("bar".to_owned()), + ], + expected: AlterDatabaseQuery::builder() + .set_name("foo".to_owned()) + .set_action(AlterDatabaseAction::RenameTo(AlterDatabaseRenameTo { + name: "bar".into(), + })) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "ALTER TABLE foo RENAME a to b".into(), + input: vec![ + Token::Table, + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::Identifier("a".to_owned()), + Token::To, + Token::Identifier("b".to_owned()), + ], + expected: AlterTableQuery::builder() + .set_table(TableName::new(None, "foo".to_owned())) + .set_action(AlterTableAction::RenameColumn(AlterTableRenameColumn { + from_name: "a".into(), + to_name: "b".into(), + })) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "오류: 빈 토큰".into(), + input: vec![], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: NULL".into(), + input: vec![ + Token::Null, + Token::Null, + Token::Null, + Token::Null, + Token::Null, + ], + expected: Default::default(), + want_error: true, + }, + ]; + + for t in test_cases { + let mut parser = Parser::new(t.input); + + let got = parser.handle_alter_query(Default::default()); + + assert_eq!( + got.is_err(), + t.want_error, + "{}: want_error: {}, error: {:?}", + t.name, + t.want_error, + got.err() + ); + + if let Ok(statements) = got { + assert_eq!(statements, t.expected.into(), "TC: {}", t.name); + } + } +} + +#[test] +fn test_handle_drop_query() { + struct TestCase { + name: String, + input: Vec, + expected: SQLStatement, + want_error: bool, + } + + let test_cases = vec![ + TestCase { + name: "DROP DATABASE foo".into(), + input: vec![Token::Database, Token::Identifier("foo".to_owned())], + expected: DropDatabaseQuery::builder() + .set_name("foo".to_owned()) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "DROP TABLE foo".into(), + input: vec![Token::Table, Token::Identifier("foo".to_owned())], + expected: DropTableQuery::builder() + .set_table(TableName::new(None, "foo".to_owned())) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "오류: 빈 토큰".into(), + input: vec![], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: NULL".into(), + input: vec![Token::Null, Token::Null], + expected: Default::default(), + want_error: true, + }, + ]; + + for t in test_cases { + let mut parser = Parser::new(t.input); + + let got = parser.handle_drop_query(Default::default()); + + assert_eq!( + got.is_err(), + t.want_error, + "{}: want_error: {}, error: {:?}", + t.name, + t.want_error, + got.err() + ); + + if let Ok(statements) = got { + assert_eq!(statements, t.expected.into(), "TC: {}", t.name); + } + } +} + +#[test] +fn test_handle_create_table_query() { + struct TestCase { + name: String, + input: Vec, + expected: SQLStatement, + want_error: bool, + } + + let test_cases = vec![ + TestCase { + name: "CREATE TABLE foo(id INT PRIMARY KEY)".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::LeftParentheses, + Token::Identifier("id".to_owned()), + Token::Identifier("INT".to_owned()), + Token::Primary, + Token::Key, + Token::RightParentheses, + ], + expected: CreateTableQuery::builder() + .set_table(TableName::new(None, "foo".to_owned())) + .add_column( + Column::builder() + .set_name("id".to_owned()) + .set_data_type(DataType::Int) + .set_primary_key(true) + .build(), + ) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "오류: 빈 토큰".into(), + input: vec![], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: CREATE TABLE foo".into(), + input: vec![Token::Identifier("foo".to_owned())], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: CREATE TABLE foo)".into(), + input: vec![Token::Identifier("foo".to_owned()), Token::RightParentheses], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: CREATE TABLE foo(".into(), + input: vec![Token::Identifier("foo".to_owned()), Token::LeftParentheses], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: CREATE TABLE foo(id INT PRIMARY KEY".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::LeftParentheses, + Token::Identifier("id".to_owned()), + Token::Identifier("INT".to_owned()), + Token::Primary, + Token::Key, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: CREATE TABLE foo(id INT PRIMARY KEY(".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::LeftParentheses, + Token::Identifier("id".to_owned()), + Token::Identifier("INT".to_owned()), + Token::Primary, + Token::Key, + Token::LeftParentheses, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: CREATE TABLE foo(id INT PRIMARY KEY))".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::LeftParentheses, + Token::Identifier("id".to_owned()), + Token::Identifier("INT".to_owned()), + Token::Primary, + Token::Key, + Token::RightParentheses, + Token::RightParentheses, + ], + expected: Default::default(), + want_error: true, + }, + ]; + + for t in test_cases { + let mut parser = Parser::new(t.input); + + let got = parser.handle_create_table_query(Default::default()); + + assert_eq!( + got.is_err(), + t.want_error, + "{}: want_error: {}, error: {:?}", + t.name, + t.want_error, + got.err() + ); + + if let Ok(statements) = got { + assert_eq!(statements, t.expected.into(), "TC: {}", t.name); + } + } +} + +#[test] +fn test_handle_alter_table_query() { + struct TestCase { + name: String, + input: Vec, + expected: SQLStatement, + want_error: bool, + } + + let test_cases = vec![ + TestCase { + name: "ALTER TABLE foo RENAME a to b".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::Identifier("a".to_owned()), + Token::To, + Token::Identifier("b".to_owned()), + ], + expected: AlterTableQuery::builder() + .set_table(TableName::new(None, "foo".to_owned())) + .set_action(AlterTableAction::RenameColumn(AlterTableRenameColumn { + from_name: "a".into(), + to_name: "b".into(), + })) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "오류: 빈 토큰".into(), + input: vec![], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "ALTER TABLE foo".into(), + input: vec![Token::Identifier("foo".to_owned())], + expected: AlterTableQuery::builder() + .set_table(TableName::new(None, "foo".to_owned())) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "ALTER TABLE foo;".into(), + input: vec![Token::Identifier("foo".to_owned()), Token::SemiColon], + expected: AlterTableQuery::builder() + .set_table(TableName::new(None, "foo".to_owned())) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "오류: ALTER TABLE foo RENAME".into(), + input: vec![Token::Identifier("foo".to_owned()), Token::Rename], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo RENAME TO".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::To, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo RENAME TO TO".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::To, + Token::To, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo RENAME COLUMN".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::Column, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo RENAME COLUMN COLUMN".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::Column, + Token::Column, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo RENAME COLUMN a".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::Column, + Token::Identifier("a".to_owned()), + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo RENAME COLUMN a DELETE".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::Column, + Token::Identifier("a".to_owned()), + Token::Delete, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo RENAME COLUMN a TO".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::Column, + Token::Identifier("a".to_owned()), + Token::To, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo RENAME COLUMN a TO DELETE".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::Column, + Token::Identifier("a".to_owned()), + Token::To, + Token::Delete, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo RENAME a".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::Identifier("a".to_owned()), + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo RENAME a NULL".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::Identifier("a".to_owned()), + Token::Null, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo RENAME a TO".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::Identifier("a".to_owned()), + Token::To, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo RENAME a TO CREATE".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::Identifier("a".to_owned()), + Token::To, + Token::Create, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo RENAME UPDATE".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Rename, + Token::Update, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo ADD".into(), + input: vec![Token::Identifier("foo".to_owned()), Token::Add], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo ADD DELETE".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Add, + Token::Delete, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo Drop".into(), + input: vec![Token::Identifier("foo".to_owned()), Token::Drop], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo Drop Drop".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Drop, + Token::Drop, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo Alter".into(), + input: vec![Token::Identifier("foo".to_owned()), Token::Alter], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo Alter bar".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Alter, + Token::Identifier("bar".to_owned()), + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo Alter bar SET".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Alter, + Token::Identifier("bar".to_owned()), + Token::Set, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo Alter bar SET DATA TYPE".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Alter, + Token::Identifier("bar".to_owned()), + Token::Set, + Token::Data, + Token::Type, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo Alter bar SET DEFAULT".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Alter, + Token::Identifier("bar".to_owned()), + Token::Set, + Token::Default, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo Alter bar SET DELETE".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Alter, + Token::Identifier("bar".to_owned()), + Token::Set, + Token::Delete, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo Alter bar DROP CREATE".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Alter, + Token::Identifier("bar".to_owned()), + Token::Drop, + Token::Create, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo Alter bar TYPE".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Alter, + Token::Identifier("bar".to_owned()), + Token::Type, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo Alter bar NULL".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Alter, + Token::Identifier("bar".to_owned()), + Token::Null, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo Alter NULL".into(), + input: vec![ + Token::Identifier("foo".to_owned()), + Token::Alter, + Token::Null, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: ALTER TABLE foo NULL".into(), + input: vec![Token::Identifier("foo".to_owned()), Token::Null], + expected: Default::default(), + want_error: true, + }, + ]; + + for t in test_cases { + let mut parser = Parser::new(t.input); + + let got = parser.handle_alter_table_query(Default::default()); + + assert_eq!( + got.is_err(), + t.want_error, + "{}: want_error: {}, error: {:?}", + t.name, + t.want_error, + got.err() + ); + + if let Ok(statements) = got { + assert_eq!(statements, t.expected.into(), "TC: {}", t.name); + } + } +} + +#[test] +fn test_handle_drop_table_query() { + struct TestCase { + name: String, + input: Vec, + expected: SQLStatement, + want_error: bool, + } + + let test_cases = vec![ + TestCase { + name: "DROP TABLE foo".into(), + input: vec![Token::Identifier("foo".to_owned())], + expected: DropTableQuery::builder() + .set_table(TableName::new(None, "foo".to_owned())) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "오류: DROP TABLE foo DROP".into(), + input: vec![Token::Identifier("foo".to_owned()), Token::Drop], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: DROP TABLE IF EXISTS".into(), + input: vec![Token::If, Token::Exists], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: 빈 토큰".into(), + input: vec![], + expected: Default::default(), + want_error: true, + }, + ]; + + for t in test_cases { + let mut parser = Parser::new(t.input); + + let got = parser.handle_drop_table_query(Default::default()); + + assert_eq!( + got.is_err(), + t.want_error, + "{}: want_error: {}, error: {:?}", + t.name, + t.want_error, + got.err() + ); + + if let Ok(statements) = got { + assert_eq!(statements, t.expected.into(), "TC: {}", t.name); + } + } +} diff --git a/src/parser/test/drop_database.rs b/src/parser/test/drop_database.rs index 0edc643f..c47bcfdb 100644 --- a/src/parser/test/drop_database.rs +++ b/src/parser/test/drop_database.rs @@ -1,24 +1,87 @@ #![cfg(test)] use crate::ast::ddl::drop_database::DropDatabaseQuery; -use crate::parser::context::ParserContext; +use crate::ast::SQLStatement; +use crate::lexer::tokens::Token; use crate::parser::predule::Parser; #[test] -pub fn drop_database() { - let text = r#" - DROP DATABASE IF exists test_db; - "# - .to_owned(); +fn test_handle_drop_database_query() { + struct TestCase { + name: String, + input: Vec, + expected: SQLStatement, + want_error: bool, + } - let mut parser = Parser::with_string(text).unwrap(); + let test_cases = vec![ + TestCase { + name: "DROP DATABASE test_db;".into(), + input: vec![Token::Identifier("test_db".to_owned()), Token::SemiColon], + expected: DropDatabaseQuery::builder() + .set_name("test_db".to_owned()) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "DROP DATABASE test_db".into(), + input: vec![Token::Identifier("test_db".to_owned())], + expected: DropDatabaseQuery::builder() + .set_name("test_db".to_owned()) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "DROP DATABASE IF EXISTS test_db;".into(), + input: vec![ + Token::If, + Token::Exists, + Token::Identifier("test_db".to_owned()), + Token::SemiColon, + ], + expected: DropDatabaseQuery::builder() + .set_name("test_db".to_owned()) + .set_if_exists(true) + .build() + .into(), + want_error: false, + }, + TestCase { + name: "오류: DROP DATABASE IF EXISTS".into(), + input: vec![Token::If, Token::Exists], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: DROP DATABASE IF EXISTS DELETE".into(), + input: vec![Token::If, Token::Exists, Token::Delete], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: "오류: DROP DATABASE test_db&&".into(), + input: vec![Token::Identifier("test_db".to_owned()), Token::And], + expected: Default::default(), + want_error: true, + }, + ]; - let expected = DropDatabaseQuery::builder() - .set_name("test_db".to_owned()) - .set_if_exists(true) - .build(); + for t in test_cases { + let mut parser = Parser::new(t.input); - assert_eq!( - parser.parse(ParserContext::default()).unwrap(), - vec![expected], - ); + let got = parser.handle_drop_database_query(); + + assert_eq!( + got.is_err(), + t.want_error, + "TC: {} Error: {:?}", + t.name, + got.err() + ); + + if let Ok(alias) = got { + assert_eq!(alias, t.expected, "TC: {}", t.name); + } + } } diff --git a/src/parser/test/mod.rs b/src/parser/test/mod.rs index 9905d7bf..094d13b6 100644 --- a/src/parser/test/mod.rs +++ b/src/parser/test/mod.rs @@ -17,3 +17,5 @@ pub(crate) mod other; pub(crate) mod tcl; pub(crate) mod common; + +pub(crate) mod ddl;