#[allow(clippy::duplicate_mod)]
#[path = "fixtures/mod.rs"]
mod fixtures;
use fixtures::{MockAccessLevel, TEST_TREE};
use nut_shell::config::{DefaultConfig, MinimalConfig, ShellConfig};
use nut_shell::shell::history::CommandHistory;
use nut_shell::tree::{CommandKind, CommandMeta, Directory, Node};
#[test]
fn test_command_history_zero_size_when_disabled() {
#[cfg(not(feature = "history"))]
{
let size = core::mem::size_of::<CommandHistory<10, 128>>();
assert_eq!(
size, 0,
"CommandHistory should be zero-size when history feature disabled, got: {} bytes",
size
);
}
#[cfg(feature = "history")]
{
let size = core::mem::size_of::<CommandHistory<10, 128>>();
assert!(
size > 0,
"CommandHistory should have non-zero size when history feature enabled"
);
}
}
#[test]
fn test_empty_history_is_zero_size() {
#[cfg(feature = "history")]
{
let size = core::mem::size_of::<CommandHistory<0, 128>>();
assert!(
size <= 24,
"CommandHistory<0> should be minimal size (Option<usize>), got: {} bytes",
size
);
}
}
#[test]
fn test_command_meta_is_const_initializable() {
const _CMD: CommandMeta<MockAccessLevel> = CommandMeta {
id: "test",
name: "test",
description: "Test command",
access_level: MockAccessLevel::Guest,
kind: CommandKind::Sync,
min_args: 0,
max_args: 0,
};
}
#[test]
fn test_directory_is_const_initializable() {
const _DIR: Directory<MockAccessLevel> = Directory {
name: "test",
children: &[],
access_level: MockAccessLevel::Guest,
};
}
#[test]
fn test_nested_tree_is_const_initializable() {
const CMD1: CommandMeta<MockAccessLevel> = CommandMeta {
id: "cmd1",
name: "cmd1",
description: "Command 1",
access_level: MockAccessLevel::Guest,
kind: CommandKind::Sync,
min_args: 0,
max_args: 0,
};
const CMD2: CommandMeta<MockAccessLevel> = CommandMeta {
id: "cmd2",
name: "cmd2",
description: "Command 2",
access_level: MockAccessLevel::User,
kind: CommandKind::Sync,
min_args: 0,
max_args: 1,
};
const SUBDIR: Directory<MockAccessLevel> = Directory {
name: "subdir",
children: &[Node::Command(&CMD2)],
access_level: MockAccessLevel::Guest,
};
const ROOT: Directory<MockAccessLevel> = Directory {
name: "/",
children: &[Node::Command(&CMD1), Node::Directory(&SUBDIR)],
access_level: MockAccessLevel::Guest,
};
assert_eq!(ROOT.name, "/");
assert_eq!(ROOT.children.len(), 2);
}
#[test]
fn test_test_tree_is_const() {
const _TREE: &Directory<MockAccessLevel> = &TEST_TREE;
assert!(
!TEST_TREE.name.is_empty(),
"TEST_TREE should be initialized"
);
assert!(
!TEST_TREE.children.is_empty(),
"TEST_TREE should have children"
);
}
#[test]
fn test_config_constants_are_zero_cost() {
struct TestConfig;
impl ShellConfig for TestConfig {
const MAX_INPUT: usize = 128;
const MAX_PATH_DEPTH: usize = 8;
const MAX_ARGS: usize = 16;
const MAX_PROMPT: usize = 64;
const MAX_RESPONSE: usize = 256;
const HISTORY_SIZE: usize = 10;
const MSG_WELCOME: &'static str = "";
const MSG_LOGIN_PROMPT: &'static str = "";
const MSG_LOGIN_SUCCESS: &'static str = "";
const MSG_LOGIN_FAILED: &'static str = "";
const MSG_LOGOUT: &'static str = "";
const MSG_INVALID_LOGIN_FORMAT: &'static str = "";
}
assert_eq!(
core::mem::size_of::<TestConfig>(),
0,
"Config structs should be zero-size"
);
}
#[test]
fn test_access_level_size() {
let size = core::mem::size_of::<MockAccessLevel>();
assert!(
size <= 4,
"AccessLevel should be small (got {} bytes), consider using #[repr(u8)]",
size
);
}
#[test]
fn test_command_meta_size_is_reasonable() {
let size = core::mem::size_of::<CommandMeta<MockAccessLevel>>();
#[cfg(target_pointer_width = "64")]
assert!(
size <= 80,
"CommandMeta size should be reasonable on 64-bit (got {} bytes)",
size
);
#[cfg(target_pointer_width = "32")]
assert!(
size <= 48,
"CommandMeta size should be reasonable on 32-bit (got {} bytes)",
size
);
}
#[test]
fn test_node_size() {
let size = core::mem::size_of::<Node<MockAccessLevel>>();
#[cfg(target_pointer_width = "64")]
assert!(
size <= 16,
"Node size should be reasonable on 64-bit (got {} bytes)",
size
);
#[cfg(target_pointer_width = "32")]
assert!(
size <= 8,
"Node size should be reasonable on 32-bit (got {} bytes)",
size
);
}
#[test]
fn test_tree_has_static_lifetime() {
let _tree_ref: &'static Directory<MockAccessLevel> = &TEST_TREE;
}
#[test]
fn test_command_meta_has_static_lifetime() {
const CMD: CommandMeta<MockAccessLevel> = CommandMeta {
id: "test",
name: "test",
description: "Test",
access_level: MockAccessLevel::Guest,
kind: CommandKind::Sync,
min_args: 0,
max_args: 0,
};
let _cmd_ref: &'static CommandMeta<MockAccessLevel> = &CMD;
}
#[test]
fn test_request_size_varies_with_features() {
use nut_shell::shell::Request;
let size = core::mem::size_of::<Request<DefaultConfig>>();
assert!(
size < 3000,
"Request size should be reasonable (got {} bytes)",
size
);
assert!(
size > 100,
"Request should have substantial size due to Command variant buffers (got {} bytes)",
size
);
}
#[test]
fn test_config_constants_are_compile_time() {
const _INPUT: usize = DefaultConfig::MAX_INPUT;
const _DEPTH: usize = DefaultConfig::MAX_PATH_DEPTH;
const _ARGS: usize = DefaultConfig::MAX_ARGS;
const _PROMPT: usize = DefaultConfig::MAX_PROMPT;
const _RESPONSE: usize = DefaultConfig::MAX_RESPONSE;
const _HISTORY: usize = DefaultConfig::HISTORY_SIZE;
}
#[test]
#[allow(clippy::assertions_on_constants)]
fn test_minimal_config_is_smaller() {
assert!(
MinimalConfig::MAX_INPUT < DefaultConfig::MAX_INPUT,
"MinimalConfig should have smaller input buffer"
);
assert!(
MinimalConfig::MAX_RESPONSE < DefaultConfig::MAX_RESPONSE,
"MinimalConfig should have smaller response buffer"
);
#[cfg(feature = "history")]
assert!(
MinimalConfig::HISTORY_SIZE < DefaultConfig::HISTORY_SIZE,
"MinimalConfig should have smaller history"
);
#[cfg(not(feature = "history"))]
assert_eq!(
MinimalConfig::HISTORY_SIZE,
DefaultConfig::HISTORY_SIZE,
"Both configs should have zero history when feature is disabled"
);
}