@@ -1697,8 +1697,215 @@ TEST_F(LuaRefTests, TableItemIsValid)
16971697 auto item2 = result ()[dynKey];
16981698 EXPECT_TRUE (item2.isValid ());
16991699
1700- // Moved-from TableItem is invalid
1700+ // After move: target is valid, source is invalid
17011701 auto moved = std::move (item2);
17021702 EXPECT_TRUE (moved.isValid ());
17031703 EXPECT_FALSE (item2.isValid ());
1704+
1705+ // Copy-constructed and copy-assigned TableItems are valid
1706+ auto copied = item;
1707+ EXPECT_TRUE (item.isValid ());
1708+ EXPECT_TRUE (copied.isValid ());
1709+ }
1710+
1711+ // --- NonMemberComparison additional coverage ---
1712+
1713+ TEST_F (LuaRefTests, NonMemberComparisonStrings)
1714+ {
1715+ luabridge::LuaRef hello (L, " hello" );
1716+ luabridge::LuaRef world (L, " world" );
1717+
1718+ // "hello" < "world" lexicographically
1719+ EXPECT_TRUE (std::string (" hello" ) < world);
1720+ EXPECT_TRUE (std::string (" hello" ) <= world);
1721+ EXPECT_FALSE (std::string (" hello" ) > world);
1722+ EXPECT_FALSE (std::string (" hello" ) >= world);
1723+
1724+ // Equal string values
1725+ EXPECT_FALSE (std::string (" hello" ) < hello);
1726+ EXPECT_TRUE (std::string (" hello" ) <= hello);
1727+ EXPECT_FALSE (std::string (" hello" ) > hello);
1728+ EXPECT_TRUE (std::string (" hello" ) >= hello);
1729+
1730+ EXPECT_FALSE (std::string (" world" ) < world);
1731+ EXPECT_TRUE (std::string (" world" ) <= world);
1732+ EXPECT_FALSE (std::string (" world" ) > world);
1733+ EXPECT_TRUE (std::string (" world" ) >= world);
1734+ }
1735+
1736+ TEST_F (LuaRefTests, NonMemberComparisonSymmetry)
1737+ {
1738+ luabridge::LuaRef seven (L, 7 );
1739+ luabridge::LuaRef eight (L, 8 );
1740+
1741+ // (T op LuaRef) must produce the same answer as (LuaRef reverse-op T)
1742+ EXPECT_EQ ((7 < eight), static_cast <bool >(eight > 7 ));
1743+ EXPECT_EQ ((7 <= eight), static_cast <bool >(eight >= 7 ));
1744+ EXPECT_EQ ((8 > seven), static_cast <bool >(seven < 8 ));
1745+ EXPECT_EQ ((8 >= seven), static_cast <bool >(seven <= 8 ));
1746+
1747+ // Equal values
1748+ EXPECT_EQ ((7 < seven), static_cast <bool >(seven > 7 ));
1749+ EXPECT_EQ ((7 <= seven), static_cast <bool >(seven >= 7 ));
1750+ EXPECT_EQ ((7 > seven), static_cast <bool >(seven < 7 ));
1751+ EXPECT_EQ ((7 >= seven), static_cast <bool >(seven <= 7 ));
1752+ }
1753+
1754+ TEST_F (LuaRefTests, NonMemberEqualityAndInequality)
1755+ {
1756+ luabridge::LuaRef seven (L, 7 );
1757+ luabridge::LuaRef eight (L, 8 );
1758+
1759+ EXPECT_TRUE (7 == seven);
1760+ EXPECT_FALSE (7 == eight);
1761+ EXPECT_FALSE (8 == seven);
1762+ EXPECT_TRUE (8 == eight);
1763+
1764+ EXPECT_FALSE (7 != seven);
1765+ EXPECT_TRUE (7 != eight);
1766+ }
1767+
1768+ // --- Hash additional coverage ---
1769+
1770+ TEST_F (LuaRefTests, HashBooleans)
1771+ {
1772+ luabridge::LuaRef t1 (L, true );
1773+ luabridge::LuaRef t2 (L, true );
1774+ luabridge::LuaRef f1 (L, false );
1775+
1776+ EXPECT_EQ (t1.hash (), t2.hash ());
1777+ EXPECT_NE (t1.hash (), f1.hash ());
1778+ }
1779+
1780+ TEST_F (LuaRefTests, HashNumbers)
1781+ {
1782+ luabridge::LuaRef a (L, 42 );
1783+ luabridge::LuaRef b (L, 42 );
1784+ luabridge::LuaRef c (L, 43 );
1785+
1786+ EXPECT_EQ (a.hash (), b.hash ());
1787+ EXPECT_NE (a.hash (), c.hash ());
1788+ }
1789+
1790+ TEST_F (LuaRefTests, HashDistinctTablesDistinct)
1791+ {
1792+ runLua (" hashT1 = {}; hashT2 = {}" );
1793+ auto t1 = luabridge::getGlobal (L, " hashT1" );
1794+ auto t2 = luabridge::getGlobal (L, " hashT2" );
1795+
1796+ EXPECT_FALSE (t1 == t2);
1797+ EXPECT_NE (t1.hash (), t2.hash ());
1798+ }
1799+
1800+ TEST_F (LuaRefTests, HashUsableInUnorderedMap)
1801+ {
1802+ std::unordered_map<luabridge::LuaRef, int > map;
1803+
1804+ luabridge::LuaRef key1 (L, " mapkey1" );
1805+ luabridge::LuaRef key2 (L, " mapkey2" );
1806+
1807+ map[key1] = 100 ;
1808+ map[key2] = 200 ;
1809+
1810+ luabridge::LuaRef key1Copy (L, " mapkey1" );
1811+ EXPECT_EQ (100 , map.at (key1Copy));
1812+ EXPECT_EQ (200 , map.at (key2));
1813+ }
1814+
1815+ // --- TableItem copy/move additional coverage ---
1816+
1817+ TEST_F (LuaRefTests, TableItemCopyAssignmentSelfAssign)
1818+ {
1819+ runLua (" result = { a = 42 }" );
1820+ auto item = result ()[" a" ];
1821+ EXPECT_TRUE (item.isValid ());
1822+
1823+ #if __clang__
1824+ #pragma clang diagnostic push
1825+ #pragma clang diagnostic ignored "-Wself-assign-overloaded"
1826+ #endif
1827+ item = item;
1828+ #if __clang__
1829+ #pragma clang diagnostic pop
1830+ #endif
1831+
1832+ EXPECT_TRUE (item.isValid ());
1833+ EXPECT_EQ (42 , item.unsafe_cast <int >());
1834+ }
1835+
1836+ TEST_F (LuaRefTests, TableItemCopyAssignmentSharesSlot)
1837+ {
1838+ // After b = a, b proxies the same table slot as a.
1839+ // Writing through b must also be visible when reading through a.
1840+ runLua (" result = { a = 1, b = 2 }" );
1841+ auto table = result ();
1842+
1843+ auto a = table[" a" ];
1844+ auto b = table[" b" ];
1845+
1846+ b = a;
1847+ EXPECT_EQ (1 , luabridge::LuaRef (b).unsafe_cast <int >());
1848+
1849+ b = 99 ;
1850+ EXPECT_EQ (99 , table[" a" ].unsafe_cast <int >());
1851+ EXPECT_EQ (99 , luabridge::LuaRef (a).unsafe_cast <int >());
1852+ }
1853+
1854+ TEST_F (LuaRefTests, TableItemMovedFromDestructible)
1855+ {
1856+ runLua (" result = { key = 1 }" );
1857+ auto item = result ()[" key" ];
1858+
1859+ auto moved = std::move (item);
1860+
1861+ EXPECT_FALSE (item.isValid ());
1862+ EXPECT_TRUE (moved.isValid ());
1863+ // item goes out of scope here — must not double-unref or crash
1864+ }
1865+
1866+ TEST_F (LuaRefTests, TableItemMoveAssignReleasesOldRefs)
1867+ {
1868+ runLua (" result = { a = 10, b = 20 }" );
1869+ auto a = result ()[" a" ];
1870+ auto b = result ()[" b" ];
1871+
1872+ b = std::move (a);
1873+
1874+ EXPECT_FALSE (a.isValid ());
1875+ EXPECT_TRUE (b.isValid ());
1876+ EXPECT_EQ (10 , luabridge::LuaRef (b).unsafe_cast <int >());
1877+ }
1878+
1879+ // --- moveTo() additional coverage ---
1880+
1881+ TEST_F (LuaRefTests, MoveToTransfersString)
1882+ {
1883+ runLua (" result = 'hello'" );
1884+ luabridge::LuaRef ref = result ();
1885+ EXPECT_TRUE (ref.isString ());
1886+
1887+ lua_State* thread = lua_newthread (L);
1888+ const int threadTop = lua_gettop (thread);
1889+
1890+ ref.moveTo (thread);
1891+
1892+ EXPECT_EQ (threadTop, lua_gettop (thread));
1893+ EXPECT_TRUE (ref.isString ());
1894+ EXPECT_EQ (" hello" , ref.cast <std::string>().valueOr (" " ));
1895+ }
1896+
1897+ TEST_F (LuaRefTests, MoveToNilRef)
1898+ {
1899+ luabridge::LuaRef nilRef (L, luabridge::LuaNil ());
1900+ EXPECT_TRUE (nilRef.isNil ());
1901+
1902+ lua_State* thread = lua_newthread (L);
1903+ const int mainTop = lua_gettop (L);
1904+ const int threadTop = lua_gettop (thread);
1905+
1906+ nilRef.moveTo (thread);
1907+
1908+ EXPECT_EQ (mainTop, lua_gettop (L));
1909+ EXPECT_EQ (threadTop, lua_gettop (thread));
1910+ EXPECT_TRUE (nilRef.isNil ());
17041911}
0 commit comments