Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,229 changes: 1,229 additions & 0 deletions packages/wasm-utxo/cli/bip-0174.mediawiki

Large diffs are not rendered by default.

138 changes: 48 additions & 90 deletions packages/wasm-utxo/cli/src/format/fixtures.rs
Original file line number Diff line number Diff line change
@@ -1,117 +1,75 @@
#[cfg(test)]
use super::tree::{node_to_string_with_scheme, ColorScheme};
#[cfg(test)]
use crate::node::Node;
#[cfg(test)]
use std::env;
#[cfg(test)]
use std::fs;
#[cfg(test)]
use std::io::{self, Write};
use std::path::PathBuf;

/// Generate a tree representation of a Node without colors
pub fn generate_tree_text(node: &Node) -> Result<String, io::Error> {
// Use the no-color scheme for consistent fixture output
/// Ensure the generated tree output matches the fixture file
/// If the fixture doesn't exist, it will be created
#[cfg(test)]
pub fn assert_tree_matches_fixture(node: &Node, name: &str) -> Result<(), io::Error> {
let no_color_scheme = ColorScheme::no_color();
node_to_string_with_scheme(node, &no_color_scheme)
}

/// Generate a tree representation of a Node with a specific color scheme
pub fn generate_tree_text_with_scheme(
node: &Node,
color_scheme: &ColorScheme,
) -> Result<String, io::Error> {
node_to_string_with_scheme(node, color_scheme)
}
let generated = node_to_string_with_scheme(node, &no_color_scheme)?;

/// Returns the path to the fixture directory
pub fn fixtures_directory() -> PathBuf {
let project_dir = env::current_dir().expect("Failed to get current directory");
project_dir.join("tests").join("fixtures")
}

/// Write tree output to a fixture file
pub fn write_fixture(name: &str, content: &str) -> Result<(), io::Error> {
let fixtures_dir = fixtures_directory();
fs::create_dir_all(&fixtures_dir)?;

let fixtures_dir = project_dir.join("test").join("fixtures");
let fixture_path = fixtures_dir.join(format!("{}.txt", name));

// Write the content to the file
let mut file = fs::File::create(&fixture_path)?;
file.write_all(content.as_bytes())?;
if fixture_path.exists() {
let fixture_content = fs::read_to_string(&fixture_path)?;
// Compare the generated output to the fixture
assert_eq!(
generated, fixture_content,
"Generated tree output doesn't match fixture file: {}",
name
);
} else {
// Create the fixture if it doesn't exist
fs::create_dir_all(&fixtures_dir)?;
let mut file = fs::File::create(&fixture_path)?;
file.write_all(generated.as_bytes())?;
println!("Created new fixture: {}.txt", name);
}

Ok(())
}

/// Read the content of a fixture file if it exists
pub fn read_fixture(name: &str) -> Result<Option<String>, io::Error> {
let fixture_path = fixtures_directory().join(format!("{}.txt", name));
/// Assert tree matches fixture, updating if needed or requested
#[cfg(test)]
pub fn assert_or_update_fixture(node: &Node, name: &str) -> Result<(), io::Error> {
let no_color_scheme = ColorScheme::no_color();
let generated = node_to_string_with_scheme(node, &no_color_scheme)?;

if fixture_path.exists() {
let content = fs::read_to_string(&fixture_path)?;
Ok(Some(content))
} else {
Ok(None)
}
}
let project_dir = env::current_dir().expect("Failed to get current directory");
let fixtures_dir = project_dir.join("test").join("fixtures");
let fixture_path = fixtures_dir.join(format!("{}.txt", name));

/// Ensure the generated tree output matches the fixture file
/// If the fixture doesn't exist, it will be created
pub fn assert_tree_matches_fixture(node: &Node, name: &str) -> Result<(), io::Error> {
let generated = generate_tree_text(node)?;
let update_fixtures = env::var("UPDATE_FIXTURES").is_ok();

match read_fixture(name)? {
Some(fixture_content) => {
// Compare the generated output to the fixture
if fixture_path.exists() {
let fixture_content = fs::read_to_string(&fixture_path)?;
if update_fixtures || generated != fixture_content {
let mut file = fs::File::create(&fixture_path)?;
file.write_all(generated.as_bytes())?;
println!("Updated fixture: {}.txt", name);
} else {
assert_eq!(
generated, fixture_content,
"Generated tree output doesn't match fixture file: {}",
name
);
}
None => {
// Create the fixture if it doesn't exist
write_fixture(name, &generated)?;
println!("Created new fixture: {}.txt", name);
}
}

Ok(())
}

/// Force update of a fixture file with new content
pub fn update_fixture(node: &Node, name: &str) -> Result<(), io::Error> {
let generated = generate_tree_text(node)?;
write_fixture(name, &generated)
}

// Environment variable to force fixture updates
const UPDATE_FIXTURES_ENV: &str = "UPDATE_FIXTURES";

/// Check if fixtures should be updated
pub fn should_update_fixtures() -> bool {
env::var(UPDATE_FIXTURES_ENV).is_ok()
}

/// Assert tree matches fixture, updating if needed or requested
pub fn assert_or_update_fixture(node: &Node, name: &str) -> Result<(), io::Error> {
let generated = generate_tree_text(node)?;

match read_fixture(name)? {
Some(fixture_content) => {
if should_update_fixtures() || generated != fixture_content {
write_fixture(name, &generated)?;
println!("Updated fixture: {}.txt", name);
} else {
assert_eq!(
generated, fixture_content,
"Generated tree output doesn't match fixture file: {}",
name
);
}
}
None => {
// Create the fixture if it doesn't exist
write_fixture(name, &generated)?;
println!("Created new fixture: {}.txt", name);
}
} else {
// Create the fixture if it doesn't exist
fs::create_dir_all(&fixtures_dir)?;
let mut file = fs::File::create(&fixture_path)?;
file.write_all(generated.as_bytes())?;
println!("Created new fixture: {}.txt", name);
}

Ok(())
Expand Down
5 changes: 1 addition & 4 deletions packages/wasm-utxo/cli/src/format/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,4 @@ pub mod fixtures;
mod tests;
mod tree;

pub use tree::{
add_node_to_tree, add_node_to_tree_with_scheme, format_primitive_for_tree, node_to_string,
node_to_string_with_scheme, render_tree, render_tree_with_scheme, ColorScheme,
};
pub use tree::{render_tree_with_scheme, ColorScheme};
222 changes: 109 additions & 113 deletions packages/wasm-utxo/cli/src/format/tests.rs
Original file line number Diff line number Diff line change
@@ -1,114 +1,110 @@
#[cfg(test)]
mod tests {
use crate::format::fixtures::assert_or_update_fixture;
use crate::node::{Node, Primitive};
use num_bigint::BigInt;

#[test]
fn test_simple_tree() -> std::io::Result<()> {
// Create a simple tree
let child1 = Node::new("name", Primitive::String("Alice".to_string()));
let child2 = Node::new("age", Primitive::U8(30));
let child3 = Node::new("active", Primitive::Boolean(true));

let mut parent = Node::new("person", Primitive::None);
parent.add_child(child1);
parent.add_child(child2);
parent.add_child(child3);

// Check against fixture
assert_or_update_fixture(&parent, "simple_tree")?;
Ok(())
}

#[test]
fn test_complex_tree() -> std::io::Result<()> {
// Create a more complex tree
let address_street = Node::new("street", Primitive::String("123 Main St".to_string()));
let address_city = Node::new("city", Primitive::String("Anytown".to_string()));
let address_zip = Node::new("zip", Primitive::U16(12345));

let mut address = Node::new("address", Primitive::None);
address.add_child(address_street);
address.add_child(address_city);
address.add_child(address_zip);

let phone1 = Node::new("home", Primitive::String("555-1234".to_string()));
let phone2 = Node::new("work", Primitive::String("555-5678".to_string()));

let mut phones = Node::new("phones", Primitive::None);
phones.add_child(phone1);
phones.add_child(phone2);

let account_number = Node::new(
"number",
Primitive::Integer(BigInt::parse_bytes(b"9876543210123456", 10).unwrap()),
);
let account_balance = Node::new("balance", Primitive::I32(5000));

let mut account = Node::new("account", Primitive::None);
account.add_child(account_number);
account.add_child(account_balance);

let name = Node::new("name", Primitive::String("John Doe".to_string()));
let age = Node::new("age", Primitive::U8(35));

let mut person = Node::new("person", Primitive::None);
person.add_child(name);
person.add_child(age);
person.add_child(address);
person.add_child(phones);
person.add_child(account);

// Check against fixture
assert_or_update_fixture(&person, "complex_tree")?;
Ok(())
}

#[test]
fn test_buffer_display() -> std::io::Result<()> {
// Test how binary data is formatted in the tree
let small_buffer = Node::new("small", Primitive::Buffer(vec![1, 2, 3, 4]));
assert_or_update_fixture(&small_buffer, "small_buffer")?;

let large_buffer = Node::new("large", Primitive::Buffer((0..100).collect()));
assert_or_update_fixture(&large_buffer, "large_buffer")?;

Ok(())
}

#[test]
fn test_numeric_types() -> std::io::Result<()> {
// Create a tree with all the numeric types
let mut numbers = Node::new("numbers", Primitive::None);

// Add signed integers
numbers.add_child(Node::new("i8_min", Primitive::I8(i8::MIN)));
numbers.add_child(Node::new("i8_max", Primitive::I8(i8::MAX)));
numbers.add_child(Node::new("i16_min", Primitive::I16(i16::MIN)));
numbers.add_child(Node::new("i16_max", Primitive::I16(i16::MAX)));
numbers.add_child(Node::new("i32_min", Primitive::I32(i32::MIN)));
numbers.add_child(Node::new("i32_max", Primitive::I32(i32::MAX)));
numbers.add_child(Node::new("i64_min", Primitive::I64(i64::MIN)));
numbers.add_child(Node::new("i64_max", Primitive::I64(i64::MAX)));

// Add unsigned integers
numbers.add_child(Node::new("u8_max", Primitive::U8(u8::MAX)));
numbers.add_child(Node::new("u16_max", Primitive::U16(u16::MAX)));
numbers.add_child(Node::new("u32_max", Primitive::U32(u32::MAX)));
numbers.add_child(Node::new("u64_max", Primitive::U64(u64::MAX)));

// Add a big integer
numbers.add_child(Node::new(
"bigint",
Primitive::Integer(
BigInt::parse_bytes(b"12345678901234567890123456789012345678901234567890", 10)
.unwrap(),
),
));

// Check against fixture
assert_or_update_fixture(&numbers, "numeric_types")?;
Ok(())
}
use crate::format::fixtures::assert_or_update_fixture;
use crate::node::{Node, Primitive};
use num_bigint::BigInt;

#[test]
fn test_simple_tree() -> std::io::Result<()> {
// Create a simple tree
let child1 = Node::new("name", Primitive::String("Alice".to_string()));
let child2 = Node::new("age", Primitive::U8(30));
let child3 = Node::new("active", Primitive::Boolean(true));

let mut parent = Node::new("person", Primitive::None);
parent.add_child(child1);
parent.add_child(child2);
parent.add_child(child3);

// Check against fixture
assert_or_update_fixture(&parent, "simple_tree")?;
Ok(())
}

#[test]
fn test_complex_tree() -> std::io::Result<()> {
// Create a more complex tree
let address_street = Node::new("street", Primitive::String("123 Main St".to_string()));
let address_city = Node::new("city", Primitive::String("Anytown".to_string()));
let address_zip = Node::new("zip", Primitive::U16(12345));

let mut address = Node::new("address", Primitive::None);
address.add_child(address_street);
address.add_child(address_city);
address.add_child(address_zip);

let phone1 = Node::new("home", Primitive::String("555-1234".to_string()));
let phone2 = Node::new("work", Primitive::String("555-5678".to_string()));

let mut phones = Node::new("phones", Primitive::None);
phones.add_child(phone1);
phones.add_child(phone2);

let account_number = Node::new(
"number",
Primitive::Integer(BigInt::parse_bytes(b"9876543210123456", 10).unwrap()),
);
let account_balance = Node::new("balance", Primitive::I32(5000));

let mut account = Node::new("account", Primitive::None);
account.add_child(account_number);
account.add_child(account_balance);

let name = Node::new("name", Primitive::String("John Doe".to_string()));
let age = Node::new("age", Primitive::U8(35));

let mut person = Node::new("person", Primitive::None);
person.add_child(name);
person.add_child(age);
person.add_child(address);
person.add_child(phones);
person.add_child(account);

// Check against fixture
assert_or_update_fixture(&person, "complex_tree")?;
Ok(())
}

#[test]
fn test_buffer_display() -> std::io::Result<()> {
// Test how binary data is formatted in the tree
let small_buffer = Node::new("small", Primitive::Buffer(vec![1, 2, 3, 4]));
assert_or_update_fixture(&small_buffer, "small_buffer")?;

let large_buffer = Node::new("large", Primitive::Buffer((0..100).collect()));
assert_or_update_fixture(&large_buffer, "large_buffer")?;

Ok(())
}

#[test]
fn test_numeric_types() -> std::io::Result<()> {
// Create a tree with all the numeric types
let mut numbers = Node::new("numbers", Primitive::None);

// Add signed integers
numbers.add_child(Node::new("i8_min", Primitive::I8(i8::MIN)));
numbers.add_child(Node::new("i8_max", Primitive::I8(i8::MAX)));
numbers.add_child(Node::new("i16_min", Primitive::I16(i16::MIN)));
numbers.add_child(Node::new("i16_max", Primitive::I16(i16::MAX)));
numbers.add_child(Node::new("i32_min", Primitive::I32(i32::MIN)));
numbers.add_child(Node::new("i32_max", Primitive::I32(i32::MAX)));
numbers.add_child(Node::new("i64_min", Primitive::I64(i64::MIN)));
numbers.add_child(Node::new("i64_max", Primitive::I64(i64::MAX)));

// Add unsigned integers
numbers.add_child(Node::new("u8_max", Primitive::U8(u8::MAX)));
numbers.add_child(Node::new("u16_max", Primitive::U16(u16::MAX)));
numbers.add_child(Node::new("u32_max", Primitive::U32(u32::MAX)));
numbers.add_child(Node::new("u64_max", Primitive::U64(u64::MAX)));

// Add a big integer
numbers.add_child(Node::new(
"bigint",
Primitive::Integer(
BigInt::parse_bytes(b"12345678901234567890123456789012345678901234567890", 10).unwrap(),
),
));

// Check against fixture
assert_or_update_fixture(&numbers, "numeric_types")?;
Ok(())
}
Loading