Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204#![allow(clippy::unwrap_used, clippy::expect_used)]
//! What `--mode` actually changes in a tool's output.//!//! The formatter's own tests cover each syntax in isolation; these pin what//! reaches a caller, which is a JSON value rather than a source snippet.
mod common;
use beamdev::server::EvalRequest;use beamdev::server::{BeamdevServer, FormatterMode};use common::{Runtime, TestNode};use rmcp::handler::server::wrapper::Parameters;use serde_json::Value;
/// Evaluates `code` against a fresh node on a server in `mode`, returning the/// `result` field a caller would receive.async fn eval_in_mode(mode: FormatterMode, code: &str) -> Value { let node = TestNode::start(Runtime::Erlang).await;
// The server connects for itself, under its own local node name. node.manager().disconnect().await;
let server = BeamdevServer::new(mode, node.name.clone(), common::COOKIE.to_string());
let result = server .tool_eval(Parameters(EvalRequest { code: code.to_string(), language: None, timeout_ms: Some(5_000), })) .await .expect("eval"); assert_ne!(result.is_error, Some(true), "{:?}", result.content);
result .structured_content .expect("structured content") .get("result") .expect("result field") .clone()}
#[tokio::test]async fn atoms_carry_each_language_s_sigil() { let code = "[ok, value].";
assert_eq!( eval_in_mode(FormatterMode::Erlang, code).await, serde_json::json!(["ok", "value"]) ); assert_eq!( eval_in_mode(FormatterMode::Elixir, code).await, serde_json::json!([":ok", ":value"]) ); assert_eq!( eval_in_mode(FormatterMode::Lfe, code).await, serde_json::json!(["'ok", "'value"]) );}
/// Gleam has no atom literal. It used to annotate one with a source comment,/// which is nonsense in a JSON value.#[tokio::test]async fn a_gleam_atom_is_a_bare_value_not_an_annotated_one() { let out = eval_in_mode(FormatterMode::Gleam, "[ok, value].").await; assert_eq!(out, serde_json::json!(["ok", "value"]));
let rendered = serde_json::to_string(&out).unwrap(); assert!( !rendered.contains("//"), "leaked a source comment: {}", rendered );}
/// A map becomes a JSON object, and its keys stay bare: only values are/// formatted, because a JSON key has to be a plain string.#[tokio::test]async fn map_keys_stay_bare_while_values_are_formatted() { let out = eval_in_mode(FormatterMode::Elixir, "#{key => value}.").await; assert_eq!(out, serde_json::json!({"key": ":value"}));}
/// A two-element tuple led by an atom is special-cased into a JSON object, so/// `{ok, V}` reads as `{"ok": V}` rather than a two-element array. As with a/// map, the key is bare.#[tokio::test]async fn an_atom_led_pair_becomes_an_object_with_a_bare_key() { let out = eval_in_mode(FormatterMode::Elixir, "{ok, value}.").await; assert_eq!(out, serde_json::json!({"ok": ":value"}));}
/// Structure is JSON in every mode: only the scalars differ.#[tokio::test]async fn lists_and_tuples_are_json_regardless_of_mode() { for mode in [ FormatterMode::Erlang, FormatterMode::Elixir, FormatterMode::Gleam, FormatterMode::Lfe, ] { let out = eval_in_mode(mode, "{1, [2, 3]}.").await; assert_eq!(out, serde_json::json!([1, [2, 3]]), "mode {}", mode); }}
#[tokio::test]async fn references_are_rendered_per_language() { let erlang = eval_in_mode(FormatterMode::Erlang, "make_ref().").await; let elixir = eval_in_mode(FormatterMode::Elixir, "make_ref().").await; let gleam = eval_in_mode(FormatterMode::Gleam, "make_ref().").await; let lfe = eval_in_mode(FormatterMode::Lfe, "make_ref().").await;
assert!(erlang.as_str().unwrap().starts_with("#Ref<"), "{}", erlang); assert!(lfe.as_str().unwrap().starts_with("#Ref<"), "{}", lfe); assert!( elixir.as_str().unwrap().starts_with("#Reference<"), "{}", elixir ); assert!(gleam.as_str().unwrap().starts_with("//ref<"), "{}", gleam);}
/// A binary of valid UTF-8 becomes a plain JSON string without the formatter/// seeing it, so only a non-UTF-8 one reaches `format_binary`.#[tokio::test]async fn a_non_utf8_binary_is_rendered_per_language() { let code = "<<255, 254, 253>>.";
assert_eq!( eval_in_mode(FormatterMode::Erlang, code).await, serde_json::json!("<<255,254,253>>") ); assert_eq!( eval_in_mode(FormatterMode::Elixir, code).await, serde_json::json!("<<255, 254, 253>>") ); assert_eq!( eval_in_mode(FormatterMode::Gleam, code).await, serde_json::json!("<<255, 254, 253>>") ); assert_eq!( eval_in_mode(FormatterMode::Lfe, code).await, serde_json::json!("#B(255 254 253)") );}
/// A bit string has no JSON equivalent, so it falls through to `format_term`.#[tokio::test]async fn a_bit_string_falls_through_to_the_formatter() { let code = "<<1:4>>.";
assert_eq!( eval_in_mode(FormatterMode::Erlang, code).await, serde_json::json!("<<4 bits>>") ); assert_eq!( eval_in_mode(FormatterMode::Elixir, code).await, serde_json::json!("<<_::4 bits>>") ); assert_eq!( eval_in_mode(FormatterMode::Gleam, code).await, serde_json::json!("<<_::4 bits>>") ); assert_eq!( eval_in_mode(FormatterMode::Lfe, code).await, serde_json::json!("#B(4 bits)") );}
/// A bit string spanning more than one byte counts the whole bytes too.#[tokio::test]async fn a_multi_byte_bit_string_counts_every_bit() { assert_eq!( eval_in_mode(FormatterMode::Erlang, "<<255, 1:4>>.").await, serde_json::json!("<<12 bits>>") );}
/// A map key that is neither an atom nor a binary has no JSON form either, so/// it is rendered by the formatter and used as the object key.#[tokio::test]async fn a_tuple_map_key_is_rendered_per_language() { let code = "#{{a, b} => 1}.";
assert_eq!( eval_in_mode(FormatterMode::Erlang, code).await, serde_json::json!({"{a, b}": 1}) ); assert_eq!( eval_in_mode(FormatterMode::Elixir, code).await, serde_json::json!({"{:a, :b}": 1}) ); assert_eq!( eval_in_mode(FormatterMode::Gleam, code).await, serde_json::json!({"#(a, b)": 1}) ); assert_eq!( eval_in_mode(FormatterMode::Lfe, code).await, serde_json::json!({"#('a 'b)": 1}) );}