diff --git a/crates/nu-command/src/filters/headers.rs b/crates/nu-command/src/filters/headers.rs index 50b318402a..8ac795bfb5 100644 --- a/crates/nu-command/src/filters/headers.rs +++ b/crates/nu-command/src/filters/headers.rs @@ -122,20 +122,42 @@ fn replace_headers(value: Value, headers: &[String]) -> Result bool { + matches!( + value, + Value::Nothing { span: _ } + | Value::String { val: _, span: _ } + | Value::Bool { val: _, span: _ } + | Value::Float { val: _, span: _ } + | Value::Int { val: _, span: _ } + ) +} + fn extract_headers(value: &Value, config: &Config) -> Result, ShellError> { match value { - Value::Record { vals, .. } => Ok(vals - .iter() - .enumerate() - .map(|(idx, value)| { - let col = value.into_string("", config); - if col.is_empty() { - format!("column{}", idx) - } else { - col + Value::Record { vals, .. } => { + for v in vals { + if !is_valid_header(v) { + return Err(ShellError::TypeMismatch( + "compatible type: Null, String, Bool, Float, Int".to_string(), + v.span()?, + )); } - }) - .collect::>()), + } + + Ok(vals + .iter() + .enumerate() + .map(|(idx, value)| { + let col = value.into_string("", config); + if col.is_empty() { + format!("column{}", idx) + } else { + col + } + }) + .collect::>()) + } Value::List { vals, span } => vals .iter() .map(|value| extract_headers(value, config)) diff --git a/crates/nu-command/tests/commands/headers.rs b/crates/nu-command/tests/commands/headers.rs index 717bdc649b..c7c9725f83 100644 --- a/crates/nu-command/tests/commands/headers.rs +++ b/crates/nu-command/tests/commands/headers.rs @@ -29,3 +29,87 @@ fn headers_adds_missing_column_name() { assert_eq!(actual.out, r#"["r1c1","r2c1"]"#) } + +#[test] +fn headers_invalid_column_type_empty_record() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + [[a b]; [{}, 2], [3,4] ] + | headers"# + )); + + assert!(actual + .err + .contains("needs compatible type: Null, String, Bool, Float, Int")); +} + +#[test] +fn headers_invalid_column_type_record() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + [[a b]; [1 ($nu.scope)] [2 2]] + | headers"# + )); + + assert!(actual + .err + .contains("needs compatible type: Null, String, Bool, Float, Int")); +} + +#[test] +fn headers_invalid_column_type_array() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + [[a b]; [[f,g], 2], [3,4] ] + | headers"# + )); + + assert!(actual + .err + .contains("needs compatible type: Null, String, Bool, Float, Int")); +} + +#[test] +fn headers_invalid_column_type_range() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + [[a b]; [(1..5), 2], [3,4] ] + | headers"# + )); + + assert!(actual + .err + .contains("needs compatible type: Null, String, Bool, Float, Int")); +} + +#[test] +fn headers_invalid_column_type_duration() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + [[a b]; [((date now) - (date now)), 2], [3,4] ] + | headers"# + )); + + assert!(actual + .err + .contains("needs compatible type: Null, String, Bool, Float, Int")); +} + +#[test] +fn headers_invalid_column_type_binary() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + [[a b]; [("aa" | into binary), 2], [3,4] ] + | headers"# + )); + + assert!(actual + .err + .contains("needs compatible type: Null, String, Bool, Float, Int")); +}