Fix tests and add some more From conversions

This commit is contained in:
Ian Manske 2024-11-17 12:47:01 -08:00
parent 7708dac4ab
commit 6c7a76b15c
7 changed files with 124 additions and 70 deletions

View File

@ -1,5 +1,5 @@
use nu_engine::command_prelude::*; use nu_engine::command_prelude::*;
use nu_protocol::format_filesize_from_conf;
use rand::{thread_rng, RngCore}; use rand::{thread_rng, RngCore};
#[derive(Clone)] #[derive(Clone)]
@ -37,7 +37,27 @@ impl Command for SubCommand {
call: &Call, call: &Call,
_input: PipelineData, _input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let length = call.req(engine_state, stack, 0)?; let length_val = call.req(engine_state, stack, 0)?;
let length = match length_val {
Value::Int { val, .. } => usize::try_from(val).map_err(|_| ShellError::InvalidValue {
valid: "a non-negative int or filesize".into(),
actual: val.to_string(),
span: length_val.span(),
}),
Value::Filesize { val, .. } => {
usize::try_from(val).map_err(|_| ShellError::InvalidValue {
valid: "a non-negative int or filesize".into(),
actual: format_filesize_from_conf(val, engine_state.get_config()),
span: length_val.span(),
})
}
val => Err(ShellError::RuntimeTypeMismatch {
expected: Type::custom("int or filesize"),
actual: val.get_type(),
span: val.span(),
}),
}?;
let mut rng = thread_rng(); let mut rng = thread_rng();
let mut out = vec![0u8; length]; let mut out = vec![0u8; length];

View File

@ -1,5 +1,5 @@
use nu_engine::command_prelude::*; use nu_engine::command_prelude::*;
use nu_protocol::format_filesize_from_conf;
use rand::{ use rand::{
distributions::{Alphanumeric, Distribution}, distributions::{Alphanumeric, Distribution},
thread_rng, thread_rng,
@ -73,14 +73,36 @@ fn chars(
call: &Call, call: &Call,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let span = call.head; let span = call.head;
let length: Option<usize> = call.get_flag(engine_state, stack, "length")?; let length: Option<Value> = call.get_flag(engine_state, stack, "length")?;
let length = if let Some(length_val) = length {
match length_val {
Value::Int { val, .. } => usize::try_from(val).map_err(|_| ShellError::InvalidValue {
valid: "a non-negative int or filesize".into(),
actual: val.to_string(),
span: length_val.span(),
}),
Value::Filesize { val, .. } => {
usize::try_from(val).map_err(|_| ShellError::InvalidValue {
valid: "a non-negative int or filesize".into(),
actual: format_filesize_from_conf(val, engine_state.get_config()),
span: length_val.span(),
})
}
val => Err(ShellError::RuntimeTypeMismatch {
expected: Type::custom("int or filesize"),
actual: val.get_type(),
span: val.span(),
}),
}?
} else {
DEFAULT_CHARS_LENGTH
};
let chars_length = length.unwrap_or(DEFAULT_CHARS_LENGTH);
let mut rng = thread_rng(); let mut rng = thread_rng();
let random_string = Alphanumeric let random_string = Alphanumeric
.sample_iter(&mut rng) .sample_iter(&mut rng)
.take(chars_length) .take(length)
.map(char::from) .map(char::from)
.collect::<String>(); .collect::<String>();

View File

@ -141,7 +141,7 @@ fn reject_rows_with_list_spread() {
let actual = nu!("let arg = [2 0]; [[name type size];[Cargo.toml file 10mb] [Cargo.lock file 10mb] [src dir 100mb]] | reject ...$arg | to nuon"); let actual = nu!("let arg = [2 0]; [[name type size];[Cargo.toml file 10mb] [Cargo.lock file 10mb] [src dir 100mb]] | reject ...$arg | to nuon");
assert_eq!( assert_eq!(
actual.out, actual.out,
r#"[[name, type, size]; ["Cargo.lock", file, 10000000b]]"# r#"[[name, type, size]; ["Cargo.lock", file, 10000000B]]"#
); );
} }
@ -150,7 +150,7 @@ fn reject_mixed_with_list_spread() {
let actual = nu!("let arg = [type 2]; [[name type size];[Cargp.toml file 10mb] [ Cargo.lock file 10mb] [src dir 100mb]] | reject ...$arg | to nuon"); let actual = nu!("let arg = [type 2]; [[name type size];[Cargp.toml file 10mb] [ Cargo.lock file 10mb] [src dir 100mb]] | reject ...$arg | to nuon");
assert_eq!( assert_eq!(
actual.out, actual.out,
r#"[[name, size]; ["Cargp.toml", 10000000b], ["Cargo.lock", 10000000b]]"# r#"[[name, size]; ["Cargp.toml", 10000000B], ["Cargo.lock", 10000000B]]"#
); );
} }

View File

@ -5,9 +5,9 @@ fn to_nuon_correct_compaction() {
let actual = nu!( let actual = nu!(
cwd: "tests/fixtures/formats", pipeline( cwd: "tests/fixtures/formats", pipeline(
r#" r#"
open appveyor.yml open appveyor.yml
| to nuon | to nuon
| str length | str length
| $in > 500 | $in > 500
"# "#
)); ));
@ -211,7 +211,7 @@ fn to_nuon_filesize() {
"# "#
)); ));
assert_eq!(actual.out, "1024b"); assert_eq!(actual.out, "1024B");
} }
#[test] #[test]

View File

@ -86,56 +86,6 @@ impl From<Filesize> for i64 {
} }
} }
impl TryFrom<u64> for Filesize {
type Error = <u64 as TryInto<i64>>::Error;
fn try_from(value: u64) -> Result<Self, Self::Error> {
value.try_into().map(Self)
}
}
impl TryFrom<Filesize> for u64 {
type Error = <i64 as TryInto<u64>>::Error;
fn try_from(filesize: Filesize) -> Result<Self, Self::Error> {
filesize.0.try_into()
}
}
/// The error type returned when a checked conversion from a floating point type fails.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Error)]
pub struct TryFromFloatError(());
impl fmt::Display for TryFromFloatError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "out of range float type conversion attempted")
}
}
impl TryFrom<f64> for Filesize {
type Error = TryFromFloatError;
fn try_from(value: f64) -> Result<Self, Self::Error> {
if i64::MIN as f64 <= value && value <= i64::MAX as f64 {
Ok(Self(value as i64))
} else {
Err(TryFromFloatError(()))
}
}
}
impl TryFrom<f32> for Filesize {
type Error = TryFromFloatError;
fn try_from(value: f32) -> Result<Self, Self::Error> {
if i64::MIN as f32 <= value && value <= i64::MAX as f32 {
Ok(Self(value as i64))
} else {
Err(TryFromFloatError(()))
}
}
}
macro_rules! impl_from { macro_rules! impl_from {
($($ty:ty),* $(,)?) => { ($($ty:ty),* $(,)?) => {
$( $(
@ -160,6 +110,68 @@ macro_rules! impl_from {
impl_from!(u8, i8, u16, i16, u32, i32); impl_from!(u8, i8, u16, i16, u32, i32);
macro_rules! impl_try_from {
($($ty:ty),* $(,)?) => {
$(
impl TryFrom<$ty> for Filesize {
type Error = <$ty as TryInto<i64>>::Error;
#[inline]
fn try_from(value: $ty) -> Result<Self, Self::Error> {
value.try_into().map(Self)
}
}
impl TryFrom<Filesize> for $ty {
type Error = <i64 as TryInto<$ty>>::Error;
#[inline]
fn try_from(filesize: Filesize) -> Result<Self, Self::Error> {
filesize.0.try_into()
}
}
)*
};
}
impl_try_from!(u64, usize, isize);
/// The error type returned when a checked conversion from a floating point type fails.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Error)]
pub struct TryFromFloatError(());
impl fmt::Display for TryFromFloatError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "out of range float type conversion attempted")
}
}
impl TryFrom<f64> for Filesize {
type Error = TryFromFloatError;
#[inline]
fn try_from(value: f64) -> Result<Self, Self::Error> {
if i64::MIN as f64 <= value && value <= i64::MAX as f64 {
Ok(Self(value as i64))
} else {
Err(TryFromFloatError(()))
}
}
}
impl TryFrom<f32> for Filesize {
type Error = TryFromFloatError;
#[inline]
fn try_from(value: f32) -> Result<Self, Self::Error> {
if i64::MIN as f32 <= value && value <= i64::MAX as f32 {
Ok(Self(value as i64))
} else {
Err(TryFromFloatError(()))
}
}
}
impl FromValue for Filesize { impl FromValue for Filesize {
fn from_value(value: Value) -> Result<Self, ShellError> { fn from_value(value: Value) -> Result<Self, ShellError> {
value.as_filesize() value.as_filesize()
@ -260,7 +272,7 @@ impl fmt::Display for Filesize {
/// All the possible filesize units for a [`Filesize`]. /// All the possible filesize units for a [`Filesize`].
/// ///
/// This type contains both units with metric (SI) decimal prefixes which are powers of 10 (e.g., KB = 1000 bytes) /// This type contains both units with metric (SI) decimal prefixes which are powers of 10 (e.g., kB = 1000 bytes)
/// and units with binary prefixes which are powers of 2 (e.g., KiB = 1024 bytes). /// and units with binary prefixes which are powers of 2 (e.g., KiB = 1024 bytes).
/// ///
/// The number of bytes in a [`FilesizeUnit`] can be obtained using /// The number of bytes in a [`FilesizeUnit`] can be obtained using
@ -330,13 +342,13 @@ impl FilesizeUnit {
/// ``` /// ```
/// # use nu_protocol::FilesizeUnit; /// # use nu_protocol::FilesizeUnit;
/// assert_eq!(FilesizeUnit::B.as_str(), "B"); /// assert_eq!(FilesizeUnit::B.as_str(), "B");
/// assert_eq!(FilesizeUnit::KB.as_str(), "KB"); /// assert_eq!(FilesizeUnit::KB.as_str(), "kB");
/// assert_eq!(FilesizeUnit::KiB.as_str(), "KiB"); /// assert_eq!(FilesizeUnit::KiB.as_str(), "KiB");
/// ``` /// ```
pub const fn as_str(&self) -> &'static str { pub const fn as_str(&self) -> &'static str {
match self { match self {
Self::B => "B", Self::B => "B",
Self::KB => "KB", Self::KB => "kB",
Self::MB => "MB", Self::MB => "MB",
Self::GB => "GB", Self::GB => "GB",
Self::TB => "TB", Self::TB => "TB",
@ -397,7 +409,7 @@ impl FromStr for FilesizeUnit {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s { Ok(match s {
"B" => Self::B, "B" => Self::B,
"KB" => Self::KB, "kB" => Self::KB,
"MB" => Self::MB, "MB" => Self::MB,
"GB" => Self::GB, "GB" => Self::GB,
"TB" => Self::TB, "TB" => Self::TB,

View File

@ -154,8 +154,8 @@ mod tests {
#[test] #[test]
fn filesize() { fn filesize() {
nuon_end_to_end("1024b", Some(Value::test_filesize(1024))); nuon_end_to_end("1024B", Some(Value::test_filesize(1024)));
assert_eq!(from_nuon("1kib", None).unwrap(), Value::test_filesize(1024),); assert_eq!(from_nuon("1kib", None).unwrap(), Value::test_filesize(1024));
} }
#[test] #[test]

View File

@ -39,7 +39,7 @@ pub enum ToStyle {
/// ///
// WARNING: please leave the following two trailing spaces, they matter for the documentation // WARNING: please leave the following two trailing spaces, they matter for the documentation
// formatting // formatting
/// > **Note** /// > **Note**
/// > a [`Span`] can be passed to [`to_nuon`] if there is context available to the caller, e.g. when /// > a [`Span`] can be passed to [`to_nuon`] if there is context available to the caller, e.g. when
/// > using this function in a command implementation such as [`to nuon`](https://www.nushell.sh/commands/docs/to_nuon.html). /// > using this function in a command implementation such as [`to nuon`](https://www.nushell.sh/commands/docs/to_nuon.html).
/// ///
@ -110,7 +110,7 @@ fn value_to_string(
// Propagate existing errors // Propagate existing errors
Value::Error { error, .. } => Err(*error.clone()), Value::Error { error, .. } => Err(*error.clone()),
// FIXME: make filesizes use the shortest lossless representation. // FIXME: make filesizes use the shortest lossless representation.
Value::Filesize { val, .. } => Ok(format!("{}b", *val)), Value::Filesize { val, .. } => Ok(format!("{}B", val.get())),
Value::Float { val, .. } => { Value::Float { val, .. } => {
// This serialises these as 'nan', 'inf' and '-inf', respectively. // This serialises these as 'nan', 'inf' and '-inf', respectively.
if &val.round() == val && val.is_finite() { if &val.round() == val && val.is_finite() {