1 """Tests for GncPrice / GncPriceDB / GncLot return-type wrapping. 3 All tests create data programmatically in in-memory sessions so they run 4 without any external data files or XML backend. 8 from datetime
import datetime
9 from unittest
import TestCase, main
28 """Base class that creates a session with a custom commodity and prices.""" 34 self.
usd = self.
table.lookup(
"CURRENCY",
"USD")
38 self.
book,
"Test Stock",
"NASDAQ",
"TSTK",
"TSTK", 10000
48 self.
price1.set_time64(datetime(2025, 1, 15))
50 self.
price1.set_typestr(
"last")
56 self.
price2.set_time64(datetime(2025, 6, 15))
58 self.
price2.set_typestr(
"last")
69 """Verify that GncPrice / GncPriceDB methods return properly wrapped 70 Python objects instead of raw SwigPyObjects.""" 74 def test_lookup_latest_returns_gnc_price(self):
76 self.assertIsNotNone(price,
"No price found for TSTK/USD")
77 self.assertIsInstance(price, GncPrice)
79 def test_nth_price_returns_gnc_price(self):
81 self.assertIsNotNone(price,
"nth_price(TSTK, 0) returned None")
82 self.assertIsInstance(price, GncPrice)
86 def test_get_commodity_returns_gnc_commodity(self):
88 self.assertIsNotNone(price)
89 comm = price.get_commodity()
90 self.assertIsInstance(comm, GncCommodity)
92 def test_get_currency_returns_gnc_commodity(self):
94 self.assertIsNotNone(price)
95 curr = price.get_currency()
96 self.assertIsInstance(curr, GncCommodity)
98 def test_get_value_returns_gnc_numeric(self):
100 self.assertIsNotNone(price)
101 val = price.get_value()
102 self.assertIsInstance(val, GncNumeric)
104 def test_clone_returns_gnc_price(self):
106 self.assertIsNotNone(price)
107 cloned = price.clone(self.
book)
108 self.assertIsInstance(cloned, GncPrice)
112 def test_lookup_latest_any_currency_returns_list_of_gnc_price(self):
114 self.assertIsInstance(prices, list)
115 self.assertGreater(len(prices), 0,
116 "Expected at least one price for TSTK")
118 self.assertIsInstance(p, GncPrice)
120 def test_get_prices_returns_list_of_gnc_price(self):
122 self.assertIsInstance(prices, list)
123 self.assertGreater(len(prices), 0)
125 self.assertIsInstance(p, GncPrice)
127 def test_lookup_nearest_in_time_any_currency(self):
128 date = datetime(2025, 1, 20)
129 prices = self.
pricedb.lookup_nearest_in_time_any_currency_t64(
131 self.assertIsInstance(prices, list)
133 self.assertIsInstance(p, GncPrice)
135 def test_lookup_nearest_before_any_currency(self):
136 date = datetime(2025, 7, 1)
137 prices = self.
pricedb.lookup_nearest_before_any_currency_t64(
139 self.assertIsInstance(prices, list)
141 self.assertIsInstance(p, GncPrice)
148 """Verify that GncLot.get_split_list() returns wrapped Split objects. 150 Creates a buy+sell pair on an account then scrubs lots, matching the 151 pattern in test_account.py's test_assignlots. 156 self.
book = self.
ses.get_book()
157 table = self.
book.get_table()
158 currency = table.lookup(
"CURRENCY",
"USD")
160 stock = GncCommodity(self.
book,
"Lot Test",
"COMMODITY",
"LTX",
"LTX", 100000)
165 root = self.
book.get_root_account()
169 cash_acct.SetCommodity(currency)
170 root.append_child(cash_acct)
172 tx = Transaction(self.
book)
174 tx.SetCurrency(currency)
175 tx.SetDateEnteredSecs(datetime.now())
176 tx.SetDatePostedSecs(datetime.now())
179 s1 = Split(self.
book)
185 s2 = Split(self.
book)
187 s2.SetAccount(cash_acct)
192 s3 = Split(self.
book)
198 s4 = Split(self.
book)
200 s4.SetAccount(cash_acct)
210 def test_lot_exists(self):
212 self.assertIsInstance(lots, list)
213 self.assertGreater(len(lots), 0,
"ScrubLots should have created a lot")
215 self.assertIsInstance(lot, GncLot)
217 def test_get_split_list_returns_splits(self):
219 self.assertGreater(len(lots), 0)
220 splits = lots[0].get_split_list()
221 self.assertIsInstance(splits, list)
222 self.assertGreater(len(splits), 0,
"Lot has no splits")
224 self.assertIsInstance(s, Split)
231 """Verify that Split methods returning gnc_numeric by value are wrapped.""" 235 self.
book = self.
ses.get_book()
236 table = self.
book.get_table()
237 currency = table.lookup(
"CURRENCY",
"USD")
239 root = self.
book.get_root_account()
241 acct.SetCommodity(currency)
242 root.append_child(acct)
245 other.SetCommodity(currency)
246 root.append_child(other)
248 tx = Transaction(self.
book)
250 tx.SetCurrency(currency)
251 tx.SetDateEnteredSecs(datetime.now())
252 tx.SetDatePostedSecs(datetime.now())
255 self.
split.SetParent(tx)
256 self.
split.SetAccount(acct)
260 s2 = Split(self.
book)
271 def test_get_noclosing_balance_returns_gnc_numeric(self):
272 val = self.
split.GetNoclosingBalance()
273 self.assertIsInstance(val, GncNumeric)
275 def test_get_cap_gains_returns_gnc_numeric(self):
276 val = self.
split.GetCapGains()
277 self.assertIsInstance(val, GncNumeric)
284 """Verify Account.get_currency_or_parent() returns GncCommodity.""" 288 self.
book = self.
ses.get_book()
289 table = self.
book.get_table()
290 self.
usd = table.lookup(
"CURRENCY",
"USD")
292 root = self.
book.get_root_account()
294 self.
acct.SetCommodity(self.
usd)
295 root.append_child(self.
acct)
300 def test_get_currency_or_parent_returns_commodity(self):
301 result = self.
acct.get_currency_or_parent()
302 self.assertIsNotNone(result)
303 self.assertIsInstance(result, GncCommodity)
310 """Verify GncCommodity.obtain_twin(book) returns GncCommodity.""" 312 def test_obtain_twin_same_book(self):
314 book = ses.get_book()
315 table = book.get_table()
316 usd = table.lookup(
"CURRENCY",
"USD")
317 self.assertIsNotNone(usd)
318 twin = usd.obtain_twin(book)
319 self.assertIsInstance(twin, GncCommodity)
327 """Verify GncCommodity.get_namespace_ds() returns 328 GncCommodityNamespace.""" 330 def test_get_namespace_ds(self):
332 book = ses.get_book()
333 table = book.get_table()
334 usd = table.lookup(
"CURRENCY",
"USD")
335 self.assertIsNotNone(usd)
336 ns = usd.get_namespace_ds()
337 self.assertIsInstance(ns, GncCommodityNamespace)
345 """Verify that passing a ClassFromFunctions wrapper to a C function 346 still works (via the SWIG typemap) and emits a DeprecationWarning.""" 349 """Passing a GncPrice wrapper to gnucash_core_c should emit 350 DeprecationWarning and still return a valid result.""" 351 from gnucash
import gnucash_core_c
as gc
355 self.skipTest(
"No price data")
357 self.assertIsInstance(price, GncPrice)
359 with warnings.catch_warnings(record=
True)
as w:
360 warnings.simplefilter(
"always")
362 comm_instance = gc.gnc_price_get_commodity(price)
363 dep_warnings = [x
for x
in w
364 if issubclass(x.category, DeprecationWarning)]
365 self.assertGreater(len(dep_warnings), 0,
366 "Expected DeprecationWarning from typemap")
369 """Passing price.instance directly should NOT emit a warning.""" 370 from gnucash
import gnucash_core_c
as gc
374 self.skipTest(
"No price data")
376 with warnings.catch_warnings(record=
True)
as w:
377 warnings.simplefilter(
"always")
378 comm_instance = gc.gnc_price_get_commodity(price.instance)
379 dep_warnings = [x
for x
in w
380 if issubclass(x.category, DeprecationWarning)]
381 self.assertEqual(len(dep_warnings), 0,
382 "Unexpected DeprecationWarning for .instance")
389 """Verify that get_latest_price, get_nearest_price, and 390 get_nearest_before_price return GncNumeric instead of raw 393 def test_get_latest_price_returns_gnc_numeric(self):
395 self.assertIsInstance(val, GncNumeric)
396 self.assertNotEqual(float(val), 0.0,
397 "Expected a non-zero price for TSTK/USD")
399 def test_get_nearest_price_returns_gnc_numeric(self):
400 date = datetime(2025, 1, 20)
402 self.assertIsInstance(val, GncNumeric)
404 def test_get_nearest_before_price_returns_gnc_numeric(self):
405 date = datetime(2025, 7, 1)
406 val = self.
pricedb.get_nearest_before_price(
408 self.assertIsInstance(val, GncNumeric)
411 """Verify the returned GncNumeric supports arithmetic.""" 414 self.assertIsInstance(doubled, GncNumeric)
415 self.assertAlmostEqual(float(doubled), float(val) * 2, places=6)
422 """Verify that passing a wrapper object as instance= to a wrapper 423 class constructor unwraps it instead of creating a broken object.""" 425 def test_gnc_numeric_double_wrap(self):
428 self.assertEqual(double.num(), 7)
429 self.assertEqual(double.denom(), 3)
431 def test_gnc_numeric_double_wrap_arithmetic(self):
435 self.assertAlmostEqual(float(result), 1.0, places=6)
437 def test_gnc_commodity_double_wrap(self):
439 book = ses.get_book()
440 table = book.get_table()
441 usd = table.lookup(
"CURRENCY",
"USD")
442 double = GncCommodity(instance=usd)
443 self.assertIsInstance(double, GncCommodity)
444 self.assertEqual(double.get_mnemonic(),
"USD")
448 """Passing a raw SWIG proxy as instance= must still work.""" 449 from gnucash
import gnucash_core_c
as gc
450 raw = gc.gnc_numeric_create(5, 2)
452 self.assertEqual(val.num(), 5)
453 self.assertEqual(val.denom(), 2)
456 if __name__ ==
'__main__':
def test_raw_instance_still_works(self)
def test_raw_instance_no_warning(self)
The primary numeric class for representing amounts and values.
def test_wrapper_triggers_deprecation_warning(self)
def test_get_latest_price_arithmetic(self)