From f7c07c15c536f896649c76b5703b432651b63699 Mon Sep 17 00:00:00 2001 From: myyrakle Date: Sun, 14 Jul 2024 21:53:56 +0900 Subject: [PATCH] =?UTF-8?q?[#119]=20Token=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/errors/execute_error.rs | 6 + src/errors/into_error.rs | 6 + src/errors/lexing_error.rs | 6 + src/errors/mod.rs | 2 +- src/errors/parsing_error.rs | 6 + src/errors/server_error.rs | 6 + src/errors/type_error.rs | 6 + src/lexer/tokens.rs | 284 ++++++++++++++++++++++++++++++++++++ 8 files changed, 321 insertions(+), 1 deletion(-) diff --git a/src/errors/execute_error.rs b/src/errors/execute_error.rs index b1689505..42b59de1 100644 --- a/src/errors/execute_error.rs +++ b/src/errors/execute_error.rs @@ -6,6 +6,12 @@ pub struct ExecuteError { pub backtrace: std::backtrace::Backtrace, } +impl PartialEq for ExecuteError { + fn eq(&self, other: &Self) -> bool { + self.message == other.message + } +} + impl ExecuteError { pub fn wrap(message: T) -> RRDBError { RRDBError::ExecuteError(Self { diff --git a/src/errors/into_error.rs b/src/errors/into_error.rs index 192db329..f282c27b 100644 --- a/src/errors/into_error.rs +++ b/src/errors/into_error.rs @@ -6,6 +6,12 @@ pub struct IntoError { pub backtrace: std::backtrace::Backtrace, } +impl PartialEq for IntoError { + fn eq(&self, other: &Self) -> bool { + self.message == other.message + } +} + impl IntoError { pub fn wrap(message: T) -> RRDBError { RRDBError::IntoError(Self { diff --git a/src/errors/lexing_error.rs b/src/errors/lexing_error.rs index 9efc1717..858f7797 100644 --- a/src/errors/lexing_error.rs +++ b/src/errors/lexing_error.rs @@ -6,6 +6,12 @@ pub struct LexingError { pub backtrace: std::backtrace::Backtrace, } +impl PartialEq for LexingError { + fn eq(&self, other: &Self) -> bool { + self.message == other.message + } +} + impl LexingError { pub fn wrap(message: T) -> RRDBError { RRDBError::LexingError(Self { diff --git a/src/errors/mod.rs b/src/errors/mod.rs index a2de2d8a..5b77bb7e 100644 --- a/src/errors/mod.rs +++ b/src/errors/mod.rs @@ -6,7 +6,7 @@ pub mod predule; pub mod server_error; pub mod type_error; -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum RRDBError { ExecuteError(execute_error::ExecuteError), IntoError(into_error::IntoError), diff --git a/src/errors/parsing_error.rs b/src/errors/parsing_error.rs index 568884dc..f8374692 100644 --- a/src/errors/parsing_error.rs +++ b/src/errors/parsing_error.rs @@ -6,6 +6,12 @@ pub struct ParsingError { pub backtrace: std::backtrace::Backtrace, } +impl PartialEq for ParsingError { + fn eq(&self, other: &Self) -> bool { + self.message == other.message + } +} + impl ParsingError { pub fn wrap(message: T) -> RRDBError { RRDBError::ParsingError(Self { diff --git a/src/errors/server_error.rs b/src/errors/server_error.rs index fb9370ea..c5f93c5f 100644 --- a/src/errors/server_error.rs +++ b/src/errors/server_error.rs @@ -4,6 +4,12 @@ pub struct ServerError { pub backtrace: std::backtrace::Backtrace, } +impl PartialEq for ServerError { + fn eq(&self, other: &Self) -> bool { + self.message == other.message + } +} + impl ServerError { pub fn new(message: T) -> Self { Self { diff --git a/src/errors/type_error.rs b/src/errors/type_error.rs index 8209e1cf..82dced4d 100644 --- a/src/errors/type_error.rs +++ b/src/errors/type_error.rs @@ -6,6 +6,12 @@ pub struct TypeError { pub backtrace: std::backtrace::Backtrace, } +impl PartialEq for TypeError { + fn eq(&self, other: &Self) -> bool { + self.message == other.message + } +} + impl TypeError { pub fn wrap(message: T) -> RRDBError { RRDBError::TypeError(Self { diff --git a/src/lexer/tokens.rs b/src/lexer/tokens.rs index 70afde68..790d2503 100644 --- a/src/lexer/tokens.rs +++ b/src/lexer/tokens.rs @@ -183,3 +183,287 @@ impl TryInto for Token { } } } + +#[cfg(test)] +mod tests { + use crate::{ + ast::dml::expressions::operators::BinaryOperator, + lexer::{predule::OperatorToken, tokens::Token}, + }; + + #[test] + fn test_token_is_unary_operator() { + let test_cases = vec![ + (Token::Operator(OperatorToken::Plus), true), + (Token::Operator(OperatorToken::Minus), true), + (Token::Operator(OperatorToken::Not), true), + (Token::And, false), + (Token::Or, false), + (Token::Like, false), + (Token::In, false), + (Token::Is, false), + (Token::Identifier("test".to_owned()), false), + (Token::Integer(1), false), + (Token::Float(1.0), false), + (Token::Boolean(true), false), + (Token::String("test".to_owned()), false), + (Token::Null, false), + (Token::LeftParentheses, false), + ]; + + for (token, want) in test_cases { + assert_eq!(token.is_unary_operator(), want); + } + } + + #[test] + fn test_token_try_into_multi_token_operator() { + struct TestCase { + name: String, + first: Token, + second: Token, + expected: BinaryOperator, + want_error: bool, + } + + let test_cases = vec![ + TestCase { + name: "NOT LIKE".into(), + first: Token::Not, + second: Token::Like, + expected: BinaryOperator::NotLike, + want_error: false, + }, + TestCase { + name: "NOT IN".into(), + first: Token::Not, + second: Token::In, + expected: BinaryOperator::NotIn, + want_error: false, + }, + TestCase { + name: "IS NOT".into(), + first: Token::Is, + second: Token::Not, + expected: BinaryOperator::IsNot, + want_error: false, + }, + TestCase { + name: "IS".into(), + first: Token::Is, + second: Token::Is, + expected: BinaryOperator::Is, + want_error: false, + }, + TestCase { + name: "NOT AND".into(), + first: Token::Not, + second: Token::And, + expected: BinaryOperator::Is, + want_error: true, + }, + TestCase { + name: "IS LIKE".into(), + first: Token::Is, + second: Token::Like, + expected: BinaryOperator::Is, + want_error: false, + }, + ]; + + for t in test_cases { + let got = t.first.try_into_multi_token_operator(t.second); + + assert_eq!( + got.is_err(), + t.want_error, + "{}: want_error: {}, error: {:?}", + t.name, + t.want_error, + got.err() + ); + + if let Ok(tokens) = got { + assert_eq!(tokens, t.expected, "TC: {}", t.name); + } + } + } + + #[test] + fn test_token_is_expression() { + struct TestCase { + name: String, + input: Token, + expected: bool, + } + + let test_cases = vec![ + TestCase { + name: "Identifier".into(), + input: Token::Identifier("test".into()), + expected: true, + }, + TestCase { + name: "Integer".into(), + input: Token::Integer(1), + expected: true, + }, + TestCase { + name: "Float".into(), + input: Token::Float(1.0), + expected: true, + }, + TestCase { + name: "Boolean".into(), + input: Token::Boolean(true), + expected: true, + }, + TestCase { + name: "String".into(), + input: Token::String("test".into()), + expected: true, + }, + TestCase { + name: "Null".into(), + input: Token::Null, + expected: true, + }, + TestCase { + name: "LeftParentheses".into(), + input: Token::LeftParentheses, + expected: true, + }, + TestCase { + name: "Not".into(), + input: Token::Not, + expected: true, + }, + TestCase { + name: "Operator".into(), + input: Token::Operator(OperatorToken::Plus), + expected: true, + }, + TestCase { + name: "And".into(), + input: Token::And, + expected: false, + }, + TestCase { + name: "Or".into(), + input: Token::Or, + expected: false, + }, + TestCase { + name: "Like".into(), + input: Token::Like, + expected: false, + }, + TestCase { + name: "In".into(), + input: Token::In, + expected: false, + }, + TestCase { + name: "Is".into(), + input: Token::Is, + expected: false, + }, + TestCase { + name: "Comma".into(), + input: Token::Comma, + expected: false, + }, + TestCase { + name: "Period".into(), + input: Token::Period, + expected: false, + }, + TestCase { + name: "SemiColon".into(), + input: Token::SemiColon, + expected: false, + }, + TestCase { + name: "RightParentheses".into(), + input: Token::RightParentheses, + expected: false, + }, + TestCase { + name: "EOF".into(), + input: Token::EOF, + expected: false, + }, + ]; + + for t in test_cases { + let got = t.input.is_expression(); + assert_eq!(got, t.expected, "TC: {}", t.name); + } + } + + #[test] + fn test_token_try_into_binary_operator() { + struct TestCase { + name: String, + input: Token, + expected: BinaryOperator, + want_error: bool, + } + + let test_cases = vec![ + TestCase { + name: "AND".into(), + input: Token::And, + expected: BinaryOperator::And, + want_error: false, + }, + TestCase { + name: "OR".into(), + input: Token::Or, + expected: BinaryOperator::Or, + want_error: false, + }, + TestCase { + name: "LIKE".into(), + input: Token::Like, + expected: BinaryOperator::Like, + want_error: false, + }, + TestCase { + name: "IN".into(), + input: Token::In, + expected: BinaryOperator::In, + want_error: false, + }, + TestCase { + name: "IS".into(), + input: Token::Is, + expected: BinaryOperator::Is, + want_error: false, + }, + TestCase { + name: "Identifier".into(), + input: Token::Identifier("test".into()), + expected: BinaryOperator::Is, + want_error: true, + }, + ]; + + for t in test_cases { + let got = TryInto::::try_into(t.input); + + assert_eq!( + got.is_err(), + t.want_error, + "{}: want_error: {}, error: {:?}", + t.name, + t.want_error, + got.err() + ); + + if let Ok(tokens) = got { + assert_eq!(tokens, t.expected, "TC: {}", t.name); + } + } + } +}