Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More test coverage #43

Merged
merged 4 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions lykiadb-lang/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ impl<'a> Parser<'a> {

fn expect_get_path(&mut self, initial: Box<Expr>, tok: TokenType) -> ParseResult<Box<Expr>> {
let mut expr = initial;

loop {
if self.match_next(&sym!(LeftParen)) {
expr = self.finish_call(expr)?;
Expand All @@ -600,7 +600,7 @@ impl<'a> Parser<'a> {
} else {
break;
}
};
}

Ok(expr)
}
Expand All @@ -609,11 +609,12 @@ impl<'a> Parser<'a> {
let expr = self.primary()?;

if let Expr::Variable { name, span, id } = expr.as_ref() {
if !name.dollar
{
if !name.dollar {
let next_tok = &self.peek_bw(0).tok_type;

if (next_tok == &sym!(Dot) || next_tok != &sym!(LeftParen)) && self.in_select_depth > 0 {
if (next_tok == &sym!(Dot) || next_tok != &sym!(LeftParen))
&& self.in_select_depth > 0
{
let head = name.clone();
let mut tail: Vec<crate::Identifier> = vec![];
while self.match_next(&sym!(Dot)) {
Expand All @@ -628,11 +629,11 @@ impl<'a> Parser<'a> {
}));
}

return Ok(self.expect_get_path(expr, sym!(DoubleColon))?);
return self.expect_get_path(expr, sym!(DoubleColon));
}
}

Ok(self.expect_get_path(expr, sym!(Dot))?)
self.expect_get_path(expr, sym!(Dot))
}

fn finish_call(&mut self, callee: Box<Expr>) -> ParseResult<Box<Expr>> {
Expand Down Expand Up @@ -777,7 +778,7 @@ impl<'a> Parser<'a> {
}

fn expected(&mut self, expected_tok_type: &TokenType) -> ParseResult<&Token> {
if self.cmp_tok(&expected_tok_type) {
if self.cmp_tok(expected_tok_type) {
return Ok(self.advance());
};
let prev_token = self.peek_bw(1);
Expand Down
2 changes: 1 addition & 1 deletion lykiadb-lang/src/tokenizer/scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ impl<'a> Scanner<'a> {

fn scan_double_token(&mut self, start: usize, c: char) -> Token {
self.advance();

if self.match_next(':') && c == ':' {
Token {
tok_type: sym!(DoubleColon),
Expand Down
14 changes: 13 additions & 1 deletion lykiadb-server/src/engine/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,12 @@ pub struct Output {
out: Vec<RV>,
}

impl Default for Output {
fn default() -> Self {
Self::new()
}
}

impl Output {
pub fn new() -> Output {
Output { out: Vec::new() }
Expand All @@ -685,7 +691,13 @@ impl Output {
}
// TODO(vck): Remove this
pub fn expect_str(&mut self, rv: Vec<String>) {
assert_eq!(self.out.iter().map(|x| x.to_string()).collect::<Vec<String>>(), rv)
assert_eq!(
self.out
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>(),
rv
)
}
}

Expand Down
64 changes: 41 additions & 23 deletions lykiadb-server/src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ impl Runtime {
}

pub mod test_helpers {
use pretty_assertions::assert_eq;
use std::collections::HashMap;
use std::sync::Arc;
use pretty_assertions::assert_eq;

use crate::engine::{Runtime, RuntimeMode, Interpreter, error::ExecutionError};
use crate::engine::{error::ExecutionError, Interpreter, Runtime, RuntimeMode};
use crate::util::{alloc_shared, Shared};
use crate::value::RV;

Expand All @@ -60,21 +60,26 @@ pub mod test_helpers {
runtime: Runtime,
}

impl Default for RuntimeTester {
fn default() -> Self {
Self::new()
}
}

impl RuntimeTester {
pub fn new() -> RuntimeTester {
let out = alloc_shared(Output::new());

RuntimeTester {
RuntimeTester {
out: out.clone(),
runtime: Runtime::new(RuntimeMode::File, Interpreter::new(Some(out), true)),
runtime: Runtime::new(RuntimeMode::File, Interpreter::new(Some(out), true)),
}
}

pub fn test_file(input: &str) {
let parts: Vec<&str> = input.split("#[").collect();

for part in parts[1..].iter() {

let mut tester = RuntimeTester::new();

let directives_and_input = part.trim();
Expand Down Expand Up @@ -111,37 +116,50 @@ pub mod test_helpers {
}

fn run_case(&mut self, case_parts: Vec<String>, flags: HashMap<&str, &str>) {

assert!(case_parts.len() > 1, "Expected at least one input/output pair");

assert!(
case_parts.len() > 1,
"Expected at least one input/output pair"
);

let mut errors: Vec<ExecutionError> = vec![];

let result = self.runtime.interpret(&case_parts[0]);

if let Err(err) = result {
errors.push(err);
}

for part in &case_parts[1..] {
if part.starts_with("err") {
assert_eq!(errors.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("\n"), part[3..].trim());
}

else if part.starts_with(">") {
assert_eq!(
errors
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join("\n"),
part[3..].trim()
);
} else if part.starts_with('>') {
let result = self.runtime.interpret(part[1..].trim());

if let Err(err) = result {
errors.push(err);
}
}
else if flags.get("run") == Some(&"plan") {
} else if flags.get("run") == Some(&"plan") {
// TODO(vck): Remove this
self.out.write().unwrap().expect(vec![RV::Str(Arc::new(part.to_string()))]);
self.out
.write()
.unwrap()
.expect(vec![RV::Str(Arc::new(part.to_string()))]);
} else {
self.out.write().unwrap().expect_str(
part.to_string()
.split('\n')
.map(|x| x.to_string())
.collect(),
);
}
else {
self.out.write().unwrap().expect_str(part.to_string().split("\n").map(|x| x.to_string()).collect());
}
}
}
}
}
}
76 changes: 76 additions & 0 deletions lykiadb-server/src/engine/stdlib/fib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,79 @@ pub fn nt_fib(_interpreter: &mut Interpreter, args: &[RV]) -> Result<RV, HaltRea
.into(),
))
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_basic_fibonacci() {
let mut interpreter = Interpreter::new(None, true);

// Test first few Fibonacci numbers
assert_eq!(
nt_fib(&mut interpreter, &[RV::Num(0.0)]).unwrap(),
RV::Num(0.0)
);
assert_eq!(
nt_fib(&mut interpreter, &[RV::Num(1.0)]).unwrap(),
RV::Num(1.0)
);
assert_eq!(
nt_fib(&mut interpreter, &[RV::Num(2.0)]).unwrap(),
RV::Num(1.0)
);
assert_eq!(
nt_fib(&mut interpreter, &[RV::Num(3.0)]).unwrap(),
RV::Num(2.0)
);
assert_eq!(
nt_fib(&mut interpreter, &[RV::Num(4.0)]).unwrap(),
RV::Num(3.0)
);
assert_eq!(
nt_fib(&mut interpreter, &[RV::Num(5.0)]).unwrap(),
RV::Num(5.0)
);
assert_eq!(
nt_fib(&mut interpreter, &[RV::Num(6.0)]).unwrap(),
RV::Num(8.0)
);
assert_eq!(
nt_fib(&mut interpreter, &[RV::Num(7.0)]).unwrap(),
RV::Num(13.0)
);
}

#[test]
fn test_invalid_input() {
let mut interpreter = Interpreter::new(None, true);

// Test with non-numeric input
let result = nt_fib(&mut interpreter, &[RV::Bool(true)]);
assert!(result.is_err());

let err = result.unwrap_err();
match err {
HaltReason::Error(e) => {
assert!(e.to_string().contains("Unexpected argument"));
}
_ => panic!("Expected InterpretError"),
}
}

#[test]
fn test_negative_input() {
let mut interpreter = Interpreter::new(None, true);

// Negative numbers should return themselves as per implementation
assert_eq!(
nt_fib(&mut interpreter, &[RV::Num(-1.0)]).unwrap(),
RV::Num(-1.0)
);
assert_eq!(
nt_fib(&mut interpreter, &[RV::Num(-5.0)]).unwrap(),
RV::Num(-5.0)
);
}
}
Loading
Loading