<commit_before>extern crate env_logger;

extern crate gluon_base as base;
extern crate gluon_parser as parser;
extern crate gluon_check as check;

use base::pos::{BytePos, CharPos, Location};
use base::types::{Type, TcType};
use check::completion;

mod support;
use support::{MockEnv, typ};

fn find_type(s: &str, location: Location) -> Result<TcType, ()> {
    let env = MockEnv::new();

    let (mut expr, result) = support::typecheck_expr(s);
    assert!(result.is_ok(), "{}", result.unwrap_err());

    completion::find(&env, &mut expr, location)
}

fn suggest(s: &str, location: Location) -> Result<Vec<String>, ()> {
    let env = MockEnv::new();

    let (mut expr, _result) = support::typecheck_partial_expr(s);
    let mut vec: Vec<String> = {
        completion::suggest(&env, &mut expr, location)
            .into_iter()
            .map(|ident| ident.name)
            .collect()
    };
    vec.sort();

    Ok(vec)
}

#[test]
fn identifier() {
    let env = MockEnv::new();

    let (mut expr, result) = support::typecheck_expr("let abc = 1 in abc");
    assert!(result.is_ok(), "{}", result.unwrap_err());

    let result = completion::find(&env,
                                  &mut expr,
                                  Location {
                                      line: 1,
                                      column: CharPos(16),
                                      absolute: BytePos(0),
                                  });
    let expected = Ok(typ("Int"));
    assert_eq!(result, expected);

    let result = completion::find(&env,
                                  &mut expr,
                                  Location {
                                      line: 1,
                                      column: CharPos(17),
                                      absolute: BytePos(0),
                                  });
    let expected = Ok(typ("Int"));
    assert_eq!(result, expected);

    let result = completion::find(&env,
                                  &mut expr,
                                  Location {
                                      line: 1,
                                      column: CharPos(18),
                                      absolute: BytePos(0),
                                  });
    let expected = Ok(typ("Int"));
    assert_eq!(result, expected);

    let result = completion::find(&env,
                                  &mut expr,
                                  Location {
                                      line: 1,
                                      column: CharPos(19),
                                      absolute: BytePos(0),
                                  });
    assert_eq!(result, Err(()));
}

#[test]
fn literal_string() {
    let result = find_type(r#" "asd" "#,
                           Location {
                               line: 1,
                               column: CharPos(2),
                               absolute: BytePos(0),
                           });
    let expected = Ok(typ("String"));

    assert_eq!(result, expected);
}

#[test]
fn in_let() {
    let result = find_type(r#"
let f x = 1
and g x = "asd"
1
"#,
                           Location {
                               line: 3,
                               column: CharPos(15),
                               absolute: BytePos(0),
                           });
    let expected = Ok(typ("String"));

    assert_eq!(result, expected);
}

#[test]
fn function_call() {
    let result = find_type(r#"
let f x = f x
1
"#,
                           Location {
                               line: 2,
                               column: CharPos(11),
                               absolute: BytePos(11),
                           });
    let expected = Ok(Type::function(vec![typ("a0")], typ("a1")));

    assert_eq!(result, expected);
}

#[test]
fn binop() {
    let env = MockEnv::new();

    let (mut expr, result) = support::typecheck_expr(r#"
let (++) l r =
    l #Int+ 1
    r #Float+ 1.0
    l
1 ++ 2.0
"#);
    assert!(result.is_ok(), "{}", result.unwrap_err());

    let result = completion::find(&env,
                                  &mut expr,
                                  Location {
                                      line: 6,
                                      column: CharPos(4),
                                      absolute: BytePos(0),
                                  });
    let expected = Ok(Type::function(vec![typ("Int"), typ("Float")], typ("Int")));
    assert_eq!(result, expected);

    let result = completion::find(&env,
                                  &mut expr,
                                  Location {
                                      line: 6,
                                      column: CharPos(1),
                                      absolute: BytePos(0),
                                  });
    let expected = Ok(typ("Int"));
    assert_eq!(result, expected);

    let result = completion::find(&env,
                                  &mut expr,
                                  Location {
                                      line: 6,
                                      column: CharPos(6),
                                      absolute: BytePos(123),
                                  });
    let expected = Ok(typ("Float"));
    assert_eq!(result, expected);
}

#[test]
fn in_record() {
    let result = find_type(r#"
{
    test = 123,
    s = "asd"
}
"#,
                           Location {
                               line: 3,
                               column: CharPos(14),
                               absolute: BytePos(0),
                           });
    let expected = Ok(typ("Int"));

    assert_eq!(result, expected);
}

#[test]
fn suggest_identifier_when_prefix() {
    let result = suggest(r#"<commit_msg>test(completion): Add tests for getting the type from a field access expression<commit_after>extern crate env_logger;

extern crate gluon_base as base;
extern crate gluon_parser as parser;
extern crate gluon_check as check;

use base::pos::{BytePos, CharPos, Location};
use base::types::{Field, Type, TcType};
use check::completion;

mod support;
use support::{MockEnv, intern, typ};

fn find_type(s: &str, location: Location) -> Result<TcType, ()> {
    let env = MockEnv::new();

    let (mut expr, result) = support::typecheck_expr(s);
    assert!(result.is_ok(), "{}", result.unwrap_err());

    completion::find(&env, &mut expr, location)
}

fn suggest(s: &str, location: Location) -> Result<Vec<String>, ()> {
    let env = MockEnv::new();

    let (mut expr, _result) = support::typecheck_partial_expr(s);
    let mut vec: Vec<String> = {
        completion::suggest(&env, &mut expr, location)
            .into_iter()
            .map(|ident| ident.name)
            .collect()
    };
    vec.sort();

    Ok(vec)
}

#[test]
fn identifier() {
    let env = MockEnv::new();

    let (mut expr, result) = support::typecheck_expr("let abc = 1 in abc");
    assert!(result.is_ok(), "{}", result.unwrap_err());

    let result = completion::find(&env,
                                  &mut expr,
                                  Location {
                                      line: 1,
                                      column: CharPos(16),
                                      absolute: BytePos(0),
                                  });
    let expected = Ok(typ("Int"));
    assert_eq!(result, expected);

    let result = completion::find(&env,
                                  &mut expr,
                                  Location {
                                      line: 1,
                                      column: CharPos(17),
                                      absolute: BytePos(0),
                                  });
    let expected = Ok(typ("Int"));
    assert_eq!(result, expected);

    let result = completion::find(&env,
                                  &mut expr,
                                  Location {
                                      line: 1,
                                      column: CharPos(18),
                                      absolute: BytePos(0),
                                  });
    let expected = Ok(typ("Int"));
    assert_eq!(result, expected);

    let result = completion::find(&env,
                                  &mut expr,
                                  Location {
                                      line: 1,
                                      column: CharPos(19),
                                      absolute: BytePos(0),
                                  });
    assert_eq!(result, Err(()));
}

#[test]
fn literal_string() {
    let result = find_type(r#" "asd" "#,
                           Location {
                               line: 1,
                               column: CharPos(2),
                               absolute: BytePos(0),
                           });
    let expected = Ok(typ("String"));

    assert_eq!(result, expected);
}

#[test]
fn in_let() {
    let result = find_type(r#"
let f x = 1
and g x = "asd"
1
"#,
                           Location {
                               line: 3,
                               column: CharPos(15),
                               absolute: BytePos(0),
                           });
    let expected = Ok(typ("String"));

    assert_eq!(result, expected);
}

#[test]
fn function_call() {
    let result = find_type(r#"
let f x = f x
1
"#,
                           Location {
                               line: 2,
                               column: CharPos(11),
                               absolute: BytePos(11),
                           });
    let expected = Ok(Type::function(vec![typ("a0")], typ("a1")));

    assert_eq!(result, expected);
}

#[test]
fn binop() {
    let env = MockEnv::new();

    let (mut expr, result) = support::typecheck_expr(r#"
let (++) l r =
    l #Int+ 1
    r #Float+ 1.0
    l
1 ++ 2.0
"#);
    assert!(result.is_ok(), "{}", result.unwrap_err());

    let result = completion::find(&env,
                                  &mut expr,
                                  Location {
                                      line: 6,
                                      column: CharPos(4),
                                      absolute: BytePos(0),
                                  });
    let expected = Ok(Type::function(vec![typ("Int"), typ("Float")], typ("Int")));
    assert_eq!(result, expected);

    let result = completion::find(&env,
                                  &mut expr,
                                  Location {
                                      line: 6,
                                      column: CharPos(1),
                                      absolute: BytePos(0),
                                  });
    let expected = Ok(typ("Int"));
    assert_eq!(result, expected);

    let result = completion::find(&env,
                                  &mut expr,
                                  Location {
                                      line: 6,
                                      column: CharPos(6),
                                      absolute: BytePos(123),
                                  });
    let expected = Ok(typ("Float"));
    assert_eq!(result, expected);
}

#[test]
fn field_access() {
    let env = ast::EmptyEnv::new();
    let typ_env = MockEnv::new();

    let (mut expr, result) = support::typecheck_expr(r#"
let r = { x = 1 }
r.x
"#);
    assert!(result.is_ok(), "{}", result.unwrap_err());

    let result = completion::find(&env,
                                  &typ_env,
                                  &mut expr,
                                  Location {
                                      line: 3,
                                      column: CharPos(1),
                                      absolute: BytePos(0),
                                  });
    let expected = Ok(Type::record(vec![],
                                   vec![Field {
                                            name: intern("x"),
                                            typ: typ("Int"),
                                        }]));
    assert_eq!(result, expected);

    let result = completion::find(&env,
                                  &typ_env,
                                  &mut expr,
                                  Location {
                                      line: 3,
                                      column: CharPos(3),
                                      absolute: BytePos(0),
                                  });
    let expected = Ok(typ("Int"));
    assert_eq!(result, expected);
}

#[test]
fn in_record() {
    let result = find_type(r#"
{
    test = 123,
    s = "asd"
}
"#,
                           Location {
                               line: 3,
                               column: CharPos(14),
                               absolute: BytePos(0),
                           });
    let expected = Ok(typ("Int"));

    assert_eq!(result, expected);
}

#[test]
fn suggest_identifier_when_prefix() {
    let result = suggest(r#"
{'fraction_non_alphanumeric': 0.12022067274538349, 'fraction_numerical': 0.00942456516742012, 'mean_word_length': 1.0138867458725505, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 104, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '890365', 'n_tokens_mistral': 3382, 'n_tokens_neox': 3187, 'n_words': 752}