#![cfg(feature = "serde")]
use bms_table::{BmsTable, BmsTableData, BmsTableHeader, CourseInfo};
use serde_json::json;
use std::collections::BTreeMap;
#[test]
fn test_build_bms_table_from_json() {
let header_json = json!({
"name": "Test Table",
"symbol": "test",
"data_url": "charts.json",
"course": [
[
{
"name": "Test Course",
"constraint": ["grade_mirror"],
"trophy": [
{
"name": "goldmedal",
"missrate": 1.0,
"scorerate": 90.0
}
],
"md5": ["test_md5_1", "test_md5_2"]
}
]
],
"level_order": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, "!i"],
"extra_field": "extra_value",
"another_field": 123
});
let data_json = json!([
{
"level": "1",
"id": 1,
"md5": "test_md5_1",
"sha256": "test_sha256_1",
"title": "Test Song",
"artist": "Test Artist",
"url": "https://example.com/test.bms",
"url_diff": "https://example.com/test_diff.bms",
"custom_field": "custom_value",
"rating": 5.0
}
]);
let header: BmsTableHeader = serde_json::from_value(header_json).unwrap();
let data: BmsTableData = serde_json::from_value(data_json).unwrap();
let bms_table = BmsTable { header, data };
assert_eq!(bms_table.header.name, "Test Table");
assert_eq!(bms_table.header.symbol, "test");
assert_eq!(bms_table.header.data_url, "charts.json");
assert_eq!(bms_table.header.course.len(), 1);
assert_eq!(bms_table.data.charts.len(), 1);
let [group] = bms_table.header.course.as_slice() else {
panic!(
"expected one course group, got {} groups: {:?}",
bms_table.header.course.len(),
bms_table.header.course
);
};
let [course] = group.as_slice() else {
panic!("expected one course, got {}: {:?}", group.len(), group);
};
assert_eq!(course.name, "Test Course");
assert_eq!(course.constraint, vec!["grade_mirror"]);
assert_eq!(course.trophy.len(), 1);
let [trophy0] = course.trophy.as_slice() else {
panic!(
"expected one trophy, got {}: {:?}",
course.trophy.len(),
course.trophy
);
};
assert_eq!(trophy0.name, "goldmedal");
assert!((trophy0.missrate - 1.0).abs() <= 1e-12);
assert!((trophy0.scorerate - 90.0).abs() <= 1e-12);
assert_eq!(course.charts.len(), 2);
let [c0, c1] = course.charts.as_slice() else {
panic!(
"expected two charts, got {}: {:?}",
course.charts.len(),
course.charts
);
};
assert_eq!(c0.md5.as_deref(), Some("test_md5_1"));
assert_eq!(c1.md5.as_deref(), Some("test_md5_2"));
let [score] = bms_table.data.charts.as_slice() else {
panic!(
"expected one chart, got {}: {:?}",
bms_table.data.charts.len(),
bms_table.data.charts
);
};
assert_eq!(score.level, "1");
assert_eq!(score.md5, Some("test_md5_1".to_string()));
assert_eq!(score.sha256, Some("test_sha256_1".to_string()));
assert_eq!(score.title, Some("Test Song".to_string()));
assert_eq!(score.artist, Some("Test Artist".to_string()));
assert_eq!(score.url, Some("https://example.com/test.bms".to_string()));
assert_eq!(
score.url_diff,
Some("https://example.com/test_diff.bms".to_string())
);
assert_eq!(
bms_table.header.extra.get("extra_field"),
Some(&json!("extra_value"))
);
assert_eq!(
bms_table.header.extra.get("another_field"),
Some(&json!(123))
);
assert!(!bms_table.header.extra.contains_key("name"));
assert_eq!(
score.extra.get("custom_field"),
Some(&json!("custom_value"))
);
assert_eq!(score.extra.get("rating"), Some(&json!(5.0)));
assert!(!score.extra.contains_key("level"));
assert_eq!(bms_table.header.level_order.len(), 22);
let [first, .., penultimate, last] = bms_table.header.level_order.as_slice() else {
panic!(
"expected at least two level_order entries, got {}: {:?}",
bms_table.header.level_order.len(),
bms_table.header.level_order
);
};
assert_eq!(first.as_str(), "0");
assert_eq!(penultimate.as_str(), "20");
assert_eq!(last.as_str(), "!i");
assert!(!bms_table.header.extra.contains_key("level_order"));
}
#[test]
fn test_build_bms_table_with_empty_fields() {
let header_json = json!({
"name": "Test Table",
"symbol": "test",
"data_url": "charts.json",
"course": []
});
let data_json = json!([
{
"level": "1",
"id": 1,
"md5": "",
"sha256": "",
"title": "",
"artist": "",
"url": "",
"url_diff": ""
}
]);
let header: BmsTableHeader = serde_json::from_value(header_json).unwrap();
let data: BmsTableData = serde_json::from_value(data_json).unwrap();
let bms_table = BmsTable { header, data };
let [score] = bms_table.data.charts.as_slice() else {
panic!(
"expected one chart, got {}: {:?}",
bms_table.data.charts.len(),
bms_table.data.charts
);
};
assert_eq!(score.level, "1");
assert_eq!(score.md5, Some("".to_string()));
assert_eq!(score.sha256, Some("".to_string()));
assert_eq!(score.title, Some("".to_string()));
assert_eq!(score.artist, Some("".to_string()));
assert_eq!(score.url, Some("".to_string()));
assert_eq!(score.url_diff, Some("".to_string()));
}
#[test]
fn test_bms_table_creation() {
let header = BmsTableHeader {
name: "Test Table".to_string(),
symbol: "test".to_string(),
data_url: "https://example.com/charts.json".to_string(),
course: vec![],
level_order: vec!["0".to_string(), "1".to_string()],
extra: BTreeMap::new(),
};
let data = BmsTableData { charts: vec![] };
let bms_table = BmsTable { header, data };
assert_eq!(bms_table.header.name, "Test Table");
assert_eq!(bms_table.header.symbol, "test");
assert_eq!(bms_table.header.course.len(), 0);
assert_eq!(bms_table.data.charts.len(), 0);
assert_eq!(bms_table.header.level_order.len(), 2);
}
#[test]
fn test_bms_table_partial_eq() {
let header1 = BmsTableHeader {
name: "Test Table".to_string(),
symbol: "test".to_string(),
data_url: "https://example.com/charts.json".to_string(),
course: vec![],
level_order: vec!["0".to_string(), "1".to_string()],
extra: BTreeMap::new(),
};
let data1 = BmsTableData { charts: vec![] };
let table1 = BmsTable {
header: header1.clone(),
data: data1,
};
let header2 = header1;
let data2 = BmsTableData { charts: vec![] };
let table2 = BmsTable {
header: header2,
data: data2,
};
assert_eq!(table1, table2);
}
#[test]
fn test_chart_item_numeric_fields_to_string() {
let data_json = json!([
{
"level": 0,
"id": 1,
"md5": "12345",
"sha256": "67890",
"title": "987",
"artist": "654",
"url": "321",
"url_diff": "111"
}
]);
let data: BmsTableData = serde_json::from_value(data_json).unwrap();
let [score] = data.charts.as_slice() else {
panic!(
"expected one chart, got {}: {:?}",
data.charts.len(),
data.charts
);
};
assert_eq!(score.level, "0");
assert_eq!(score.md5, Some("12345".to_string()));
assert_eq!(score.sha256, Some("67890".to_string()));
assert_eq!(score.title, Some("987".to_string()));
assert_eq!(score.artist, Some("654".to_string()));
assert_eq!(score.url, Some("321".to_string()));
assert_eq!(score.url_diff, Some("111".to_string()));
}
#[test]
fn test_build_bms_table_invalid_json() {
let header_json = json!({
"name": "Test Table",
"symbol": "test",
"data_url": "charts.json"
});
let data_json = json!([
{
"level": "1",
"id": 1
}
]);
let header: BmsTableHeader = serde_json::from_value(header_json).unwrap();
let data: BmsTableData = serde_json::from_value(data_json).unwrap();
let _bms_table = BmsTable { header, data };
}
#[test]
fn test_bms_table_header_deserialize_vec_course_info() {
let json_data = r#"{
"name": "Test Table",
"symbol": "test",
"data_url": "score.json",
"course": [
{
"name": "Course 1",
"constraint": ["grade_mirror"],
"trophy": [
{
"name": "goldmedal",
"missrate": 5.0,
"scorerate": 70.0
}
],
"md5": ["abc123", "def456"]
}
]
}"#;
let result: serde_json::Result<BmsTableHeader> = serde_json::from_str(json_data);
assert!(result.is_ok());
let header = result.unwrap();
assert_eq!(header.name, "Test Table");
assert_eq!(header.symbol, "test");
assert_eq!(header.data_url, "score.json");
assert_eq!(header.course.len(), 1);
assert_eq!(header.course.first().map(std::vec::Vec::len), Some(1));
let [group] = header.course.as_slice() else {
panic!(
"expected one group, got {}: {:?}",
header.course.len(),
header.course
);
};
let [course] = group.as_slice() else {
panic!("expected one course, got {}: {:?}", group.len(), group);
};
assert_eq!(course.name.as_str(), "Course 1");
assert_eq!(course.charts.len(), 2);
let [c0, c1] = course.charts.as_slice() else {
panic!(
"expected two charts, got {}: {:?}",
course.charts.len(),
course.charts
);
};
assert_eq!(c0.md5.as_deref(), Some("abc123"));
assert_eq!(c1.md5.as_deref(), Some("def456"));
}
#[test]
fn test_bms_table_header_deserialize_vec_vec_course_info() {
let json_data = r#"{
"name": "Test Table",
"symbol": "test",
"data_url": "score.json",
"course": [
[
{
"name": "Course 1",
"constraint": ["grade_mirror"],
"trophy": [
{
"name": "goldmedal",
"missrate": 5.0,
"scorerate": 70.0
}
],
"md5": ["abc123", "def456"]
}
],
[
{
"name": "Course 2",
"constraint": ["ln"],
"trophy": [
{
"name": "silvermedal",
"missrate": 10.0,
"scorerate": 60.0
}
],
"md5": ["ghi789"]
}
]
]
}"#;
let result: serde_json::Result<BmsTableHeader> = serde_json::from_str(json_data);
assert!(result.is_ok());
let header = result.unwrap();
assert_eq!(header.name, "Test Table");
assert_eq!(header.symbol, "test");
assert_eq!(header.data_url, "score.json");
assert_eq!(header.course.len(), 2);
let [group1, group2] = header.course.as_slice() else {
panic!(
"expected two groups, got {}: {:?}",
header.course.len(),
header.course
);
};
let [course1] = group1.as_slice() else {
panic!(
"expected one course in group1, got {}: {:?}",
group1.len(),
group1
);
};
let [course2] = group2.as_slice() else {
panic!(
"expected one course in group2, got {}: {:?}",
group2.len(),
group2
);
};
assert_eq!(course1.name.as_str(), "Course 1");
assert_eq!(course2.name.as_str(), "Course 2");
assert_eq!(course1.charts.len(), 2);
let [c10, c11] = course1.charts.as_slice() else {
panic!(
"expected two charts, got {}: {:?}",
course1.charts.len(),
course1.charts
);
};
assert_eq!(c10.md5.as_deref(), Some("abc123"));
assert_eq!(c11.md5.as_deref(), Some("def456"));
assert_eq!(course2.charts.len(), 1);
let [c20] = course2.charts.as_slice() else {
panic!(
"expected one chart, got {}: {:?}",
course2.charts.len(),
course2.charts
);
};
assert_eq!(c20.md5.as_deref(), Some("ghi789"));
}
#[test]
fn test_course_info_deserialize_charts_with_default_level() {
let json_data = r#"{
"name": "Test Course",
"constraint": ["grade_mirror"],
"trophy": [
{
"name": "goldmedal",
"missrate": 5.0,
"scorerate": 70.0
}
],
"charts": [
{
"title": "Test Song",
"artist": "Test Artist",
"url": "https://example.com/test.bms"
},
{
"level": "1",
"title": "Test Song 2",
"artist": "Test Artist 2",
"url": "https://example.com/test2.bms"
}
]
}"#;
let result: serde_json::Result<CourseInfo> = serde_json::from_str(json_data);
assert!(result.is_ok());
let course_info = result.unwrap();
assert_eq!(course_info.name, "Test Course");
assert_eq!(course_info.constraint, vec!["grade_mirror"]);
assert_eq!(course_info.trophy.len(), 1);
assert_eq!(course_info.charts.len(), 2);
let [first_chart, second_chart] = course_info.charts.as_slice() else {
panic!(
"expected two charts, got {}: {:?}",
course_info.charts.len(),
course_info.charts
);
};
assert_eq!(first_chart.level, "0");
assert_eq!(first_chart.title, Some("Test Song".to_string()));
assert_eq!(first_chart.artist, Some("Test Artist".to_string()));
assert_eq!(second_chart.level, "1");
assert_eq!(second_chart.title, Some("Test Song 2".to_string()));
assert_eq!(second_chart.artist, Some("Test Artist 2".to_string()));
}
#[test]
fn test_course_info_deserialize_sha256list_to_charts() {
let json_data = r#"{
"name": "Test Course",
"constraint": ["grade_mirror"],
"trophy": [
{
"name": "goldmedal",
"missrate": 5.0,
"scorerate": 70.0
}
],
"sha256": ["sha256_hash_1", "sha256_hash_2"]
}"#;
let result: serde_json::Result<CourseInfo> = serde_json::from_str(json_data);
assert!(result.is_ok());
let course_info = result.unwrap();
assert_eq!(course_info.name, "Test Course");
assert_eq!(course_info.constraint, vec!["grade_mirror"]);
assert_eq!(course_info.trophy.len(), 1);
assert_eq!(course_info.charts.len(), 2);
let [c0, c1] = course_info.charts.as_slice() else {
panic!(
"expected two charts, got {}: {:?}",
course_info.charts.len(),
course_info.charts
);
};
assert_eq!(c0.sha256.as_deref(), Some("sha256_hash_1"));
assert_eq!(c1.sha256.as_deref(), Some("sha256_hash_2"));
assert_eq!(c0.md5.as_deref(), None);
assert_eq!(c1.md5.as_deref(), None);
}
#[test]
fn test_course_info_deserialize_md5_and_sha256_to_charts() {
let json_data = r#"{
"name": "Test Course",
"constraint": ["grade_mirror"],
"trophy": [
{
"name": "goldmedal",
"missrate": 5.0,
"scorerate": 70.0
}
],
"md5": ["md5_hash_1"],
"sha256": ["sha256_hash_1"],
"charts": [
{
"level": "2",
"title": "Existing Chart",
"artist": "Test Artist"
}
]
}"#;
let result: serde_json::Result<CourseInfo> = serde_json::from_str(json_data);
assert!(result.is_ok());
let course_info = result.unwrap();
assert_eq!(course_info.name, "Test Course");
assert_eq!(course_info.constraint, vec!["grade_mirror"]);
assert_eq!(course_info.trophy.len(), 1);
assert_eq!(course_info.charts.len(), 3);
let [existing, from_md5, from_sha256] = course_info.charts.as_slice() else {
panic!(
"expected three charts, got {}: {:?}",
course_info.charts.len(),
course_info.charts
);
};
assert_eq!(existing.level.as_str(), "2");
assert_eq!(existing.title.as_deref(), Some("Existing Chart"));
assert_eq!(existing.artist.as_deref(), Some("Test Artist"));
assert_eq!(from_md5.md5.as_deref(), Some("md5_hash_1"));
assert_eq!(from_md5.level.as_str(), "0");
assert_eq!(from_sha256.sha256.as_deref(), Some("sha256_hash_1"));
assert_eq!(from_sha256.level.as_str(), "0");
}
#[test]
fn test_json_serialization() {
let header = bms_table::BmsTableHeader {
name: "Test Table".to_string(),
symbol: "test".to_string(),
data_url: "charts.json".to_string(),
course: vec![],
level_order: vec!["0".to_string(), "1".to_string(), "!i".to_string()],
extra: BTreeMap::new(),
};
let json = serde_json::to_string(&header).unwrap();
let parsed: bms_table::BmsTableHeader = serde_json::from_str(&json).unwrap();
let mut expected = header;
expected.course = vec![Vec::new()];
assert_eq!(expected, parsed);
}