Skip to content

Commit 50f94db

Browse files
sanityclaude
andauthored
test: add unit tests for PutOp and GetOp operations (#2223)
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 2918ebf commit 50f94db

File tree

5 files changed

+935
-0
lines changed

5 files changed

+935
-0
lines changed

crates/core/src/operations/get.rs

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1647,3 +1647,215 @@ mod messages {
16471647
}
16481648
}
16491649
}
1650+
1651+
#[cfg(test)]
1652+
mod tests {
1653+
use super::*;
1654+
use crate::message::Transaction;
1655+
use crate::operations::test_utils::{make_contract_key, make_peer};
1656+
use std::collections::HashSet;
1657+
1658+
fn make_get_op(state: Option<GetState>, result: Option<GetResult>) -> GetOp {
1659+
GetOp {
1660+
id: Transaction::new::<GetMsg>(),
1661+
state,
1662+
result,
1663+
stats: None,
1664+
upstream_addr: None,
1665+
}
1666+
}
1667+
1668+
// Tests for finalized() method
1669+
#[test]
1670+
fn get_op_finalized_when_finished_with_result() {
1671+
let key = make_contract_key(1);
1672+
let result = GetResult {
1673+
key,
1674+
state: WrappedState::new(vec![1, 2, 3]),
1675+
contract: None,
1676+
};
1677+
let op = make_get_op(Some(GetState::Finished { key }), Some(result));
1678+
assert!(
1679+
op.finalized(),
1680+
"GetOp should be finalized when state is Finished and result is present"
1681+
);
1682+
}
1683+
1684+
#[test]
1685+
fn get_op_not_finalized_when_finished_without_result() {
1686+
let key = make_contract_key(1);
1687+
let op = make_get_op(Some(GetState::Finished { key }), None);
1688+
assert!(
1689+
!op.finalized(),
1690+
"GetOp should not be finalized when state is Finished but result is None"
1691+
);
1692+
}
1693+
1694+
#[test]
1695+
fn get_op_not_finalized_when_received_request() {
1696+
let op = make_get_op(Some(GetState::ReceivedRequest { requester: None }), None);
1697+
assert!(
1698+
!op.finalized(),
1699+
"GetOp should not be finalized in ReceivedRequest state"
1700+
);
1701+
}
1702+
1703+
#[test]
1704+
fn get_op_not_finalized_when_state_is_none() {
1705+
let op = make_get_op(None, None);
1706+
assert!(
1707+
!op.finalized(),
1708+
"GetOp should not be finalized when state is None"
1709+
);
1710+
}
1711+
1712+
// Tests for to_host_result() method
1713+
#[test]
1714+
fn get_op_to_host_result_success_when_result_present() {
1715+
let key = make_contract_key(1);
1716+
let state_data = WrappedState::new(vec![1, 2, 3]);
1717+
let result = GetResult {
1718+
key,
1719+
state: state_data.clone(),
1720+
contract: None,
1721+
};
1722+
let op = make_get_op(Some(GetState::Finished { key }), Some(result));
1723+
let host_result = op.to_host_result();
1724+
1725+
assert!(
1726+
host_result.is_ok(),
1727+
"to_host_result should return Ok when result is present"
1728+
);
1729+
1730+
if let Ok(HostResponse::ContractResponse(
1731+
freenet_stdlib::client_api::ContractResponse::GetResponse {
1732+
key: returned_key,
1733+
state: returned_state,
1734+
..
1735+
},
1736+
)) = host_result
1737+
{
1738+
assert_eq!(returned_key, key, "Returned key should match");
1739+
assert_eq!(returned_state, state_data, "Returned state should match");
1740+
} else {
1741+
panic!("Expected GetResponse");
1742+
}
1743+
}
1744+
1745+
#[test]
1746+
fn get_op_to_host_result_error_when_no_result() {
1747+
let op = make_get_op(Some(GetState::ReceivedRequest { requester: None }), None);
1748+
let result = op.to_host_result();
1749+
assert!(
1750+
result.is_err(),
1751+
"to_host_result should return Err when result is None"
1752+
);
1753+
}
1754+
1755+
// Tests for outcome() method - partial coverage since full stats require complex setup
1756+
#[test]
1757+
fn get_op_outcome_incomplete_without_stats() {
1758+
let key = make_contract_key(1);
1759+
let result = GetResult {
1760+
key,
1761+
state: WrappedState::new(vec![]),
1762+
contract: None,
1763+
};
1764+
let op = make_get_op(Some(GetState::Finished { key }), Some(result));
1765+
let outcome = op.outcome();
1766+
1767+
assert!(matches!(outcome, OpOutcome::Incomplete));
1768+
}
1769+
1770+
// Tests for GetMsg helper methods
1771+
#[test]
1772+
fn get_msg_target_addr_returns_socket_for_request_get() {
1773+
let target = make_peer(5000);
1774+
let msg = GetMsg::RequestGet {
1775+
id: Transaction::new::<GetMsg>(),
1776+
target: target.clone(),
1777+
key: make_contract_key(1),
1778+
fetch_contract: false,
1779+
skip_list: HashSet::new(),
1780+
};
1781+
assert_eq!(
1782+
msg.target_addr(),
1783+
target.socket_addr(),
1784+
"target_addr should return target's socket address for RequestGet"
1785+
);
1786+
}
1787+
1788+
#[test]
1789+
fn get_msg_target_addr_returns_socket_for_return_get() {
1790+
let target = make_peer(6000);
1791+
let msg = GetMsg::ReturnGet {
1792+
id: Transaction::new::<GetMsg>(),
1793+
key: make_contract_key(1),
1794+
value: StoreResponse {
1795+
state: None,
1796+
contract: None,
1797+
},
1798+
target: target.clone(),
1799+
skip_list: HashSet::new(),
1800+
};
1801+
assert_eq!(
1802+
msg.target_addr(),
1803+
target.socket_addr(),
1804+
"target_addr should return target's socket address for ReturnGet"
1805+
);
1806+
}
1807+
1808+
#[test]
1809+
fn get_msg_id_returns_transaction() {
1810+
let tx = Transaction::new::<GetMsg>();
1811+
let msg = GetMsg::RequestGet {
1812+
id: tx,
1813+
target: make_peer(5000),
1814+
key: make_contract_key(1),
1815+
fetch_contract: false,
1816+
skip_list: HashSet::new(),
1817+
};
1818+
assert_eq!(*msg.id(), tx, "id() should return the transaction ID");
1819+
}
1820+
1821+
#[test]
1822+
fn get_msg_display_formats_correctly() {
1823+
let tx = Transaction::new::<GetMsg>();
1824+
let msg = GetMsg::SeekNode {
1825+
id: tx,
1826+
key: make_contract_key(1),
1827+
fetch_contract: false,
1828+
target: make_peer(5000),
1829+
htl: 5,
1830+
skip_list: HashSet::new(),
1831+
};
1832+
let display = format!("{}", msg);
1833+
assert!(
1834+
display.contains("SeekNode"),
1835+
"Display should contain message type name"
1836+
);
1837+
}
1838+
1839+
// Tests for GetState Display
1840+
#[test]
1841+
fn get_state_display_received_request() {
1842+
let state = GetState::ReceivedRequest { requester: None };
1843+
let display = format!("{}", state);
1844+
assert!(
1845+
display.contains("ReceivedRequest"),
1846+
"Display should contain state name"
1847+
);
1848+
}
1849+
1850+
#[test]
1851+
fn get_state_display_finished() {
1852+
let state = GetState::Finished {
1853+
key: make_contract_key(1),
1854+
};
1855+
let display = format!("{}", state);
1856+
assert!(
1857+
display.contains("Finished"),
1858+
"Display should contain state name"
1859+
);
1860+
}
1861+
}

crates/core/src/operations/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ pub(crate) mod connect;
2020
pub(crate) mod get;
2121
pub(crate) mod put;
2222
pub(crate) mod subscribe;
23+
#[cfg(test)]
24+
pub(crate) mod test_utils;
2325
pub(crate) mod update;
2426

2527
pub(crate) trait Operation

crates/core/src/operations/put.rs

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1744,3 +1744,166 @@ mod messages {
17441744
}
17451745
}
17461746
}
1747+
1748+
#[cfg(test)]
1749+
mod tests {
1750+
use super::*;
1751+
use crate::message::Transaction;
1752+
use crate::operations::test_utils::{make_contract_key, make_peer};
1753+
1754+
fn make_put_op(state: Option<PutState>) -> PutOp {
1755+
PutOp {
1756+
id: Transaction::new::<PutMsg>(),
1757+
state,
1758+
upstream_addr: None,
1759+
}
1760+
}
1761+
1762+
// Tests for finalized() method
1763+
#[test]
1764+
fn put_op_finalized_when_state_is_none() {
1765+
let op = make_put_op(None);
1766+
assert!(
1767+
op.finalized(),
1768+
"PutOp should be finalized when state is None"
1769+
);
1770+
}
1771+
1772+
#[test]
1773+
fn put_op_finalized_when_state_is_finished() {
1774+
let op = make_put_op(Some(PutState::Finished {
1775+
key: make_contract_key(1),
1776+
}));
1777+
assert!(
1778+
op.finalized(),
1779+
"PutOp should be finalized when state is Finished"
1780+
);
1781+
}
1782+
1783+
#[test]
1784+
fn put_op_not_finalized_when_received_request() {
1785+
let op = make_put_op(Some(PutState::ReceivedRequest));
1786+
assert!(
1787+
!op.finalized(),
1788+
"PutOp should not be finalized in ReceivedRequest state"
1789+
);
1790+
}
1791+
1792+
#[test]
1793+
fn put_op_not_finalized_when_broadcast_ongoing() {
1794+
let op = make_put_op(Some(PutState::BroadcastOngoing));
1795+
assert!(
1796+
!op.finalized(),
1797+
"PutOp should not be finalized in BroadcastOngoing state"
1798+
);
1799+
}
1800+
1801+
// Tests for to_host_result() method
1802+
#[test]
1803+
fn put_op_to_host_result_success_when_finished() {
1804+
let key = make_contract_key(1);
1805+
let op = make_put_op(Some(PutState::Finished { key }));
1806+
let result = op.to_host_result();
1807+
assert!(
1808+
result.is_ok(),
1809+
"to_host_result should return Ok for Finished state"
1810+
);
1811+
1812+
if let Ok(HostResponse::ContractResponse(
1813+
freenet_stdlib::client_api::ContractResponse::PutResponse { key: returned_key },
1814+
)) = result
1815+
{
1816+
assert_eq!(returned_key, key, "Returned key should match");
1817+
} else {
1818+
panic!("Expected PutResponse");
1819+
}
1820+
}
1821+
1822+
#[test]
1823+
fn put_op_to_host_result_error_when_not_finished() {
1824+
let op = make_put_op(Some(PutState::ReceivedRequest));
1825+
let result = op.to_host_result();
1826+
assert!(
1827+
result.is_err(),
1828+
"to_host_result should return Err for non-Finished state"
1829+
);
1830+
}
1831+
1832+
#[test]
1833+
fn put_op_to_host_result_error_when_none() {
1834+
let op = make_put_op(None);
1835+
let result = op.to_host_result();
1836+
assert!(
1837+
result.is_err(),
1838+
"to_host_result should return Err when state is None"
1839+
);
1840+
}
1841+
1842+
// Tests for is_completed() trait method
1843+
#[test]
1844+
fn put_op_is_completed_when_finished() {
1845+
let op = make_put_op(Some(PutState::Finished {
1846+
key: make_contract_key(1),
1847+
}));
1848+
assert!(
1849+
op.is_completed(),
1850+
"is_completed should return true for Finished state"
1851+
);
1852+
}
1853+
1854+
#[test]
1855+
fn put_op_is_not_completed_when_in_progress() {
1856+
let op = make_put_op(Some(PutState::ReceivedRequest));
1857+
assert!(
1858+
!op.is_completed(),
1859+
"is_completed should return false for ReceivedRequest state"
1860+
);
1861+
}
1862+
1863+
// Tests for PutMsg helper methods
1864+
#[test]
1865+
fn put_msg_target_addr_returns_socket_for_successful_put() {
1866+
let target = make_peer(5000);
1867+
let origin = make_peer(6000);
1868+
let msg = PutMsg::SuccessfulPut {
1869+
id: Transaction::new::<PutMsg>(),
1870+
target: target.clone(),
1871+
key: make_contract_key(1),
1872+
origin,
1873+
};
1874+
assert_eq!(
1875+
msg.target_addr(),
1876+
target.socket_addr(),
1877+
"target_addr should return target's socket address for SuccessfulPut"
1878+
);
1879+
}
1880+
1881+
#[test]
1882+
fn put_msg_target_addr_returns_none_for_await_put() {
1883+
let msg = PutMsg::AwaitPut {
1884+
id: Transaction::new::<PutMsg>(),
1885+
};
1886+
assert!(
1887+
msg.target_addr().is_none(),
1888+
"target_addr should return None for AwaitPut message"
1889+
);
1890+
}
1891+
1892+
#[test]
1893+
fn put_msg_id_returns_transaction() {
1894+
let tx = Transaction::new::<PutMsg>();
1895+
let msg = PutMsg::AwaitPut { id: tx };
1896+
assert_eq!(*msg.id(), tx, "id() should return the transaction ID");
1897+
}
1898+
1899+
#[test]
1900+
fn put_msg_display_formats_correctly() {
1901+
let tx = Transaction::new::<PutMsg>();
1902+
let msg = PutMsg::AwaitPut { id: tx };
1903+
let display = format!("{}", msg);
1904+
assert!(
1905+
display.contains("AwaitPut"),
1906+
"Display should contain message type name"
1907+
);
1908+
}
1909+
}

0 commit comments

Comments
 (0)