Skip to content

Commit

Permalink
Merge branch 'maint-progress2' into maint #1311
Browse files Browse the repository at this point in the history
  • Loading branch information
christopherlam committed Apr 10, 2022
2 parents 6a668df + 40d5db4 commit d022651
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 11 deletions.
63 changes: 52 additions & 11 deletions bindings/guile/gnc-kvp-guile.cpp
@@ -1,6 +1,7 @@
#include <guid.hpp>
#include <kvp-frame.hpp>
#include <libguile.h>
#include <numeric>

extern "C"
{
Expand All @@ -21,6 +22,17 @@ extern "C"
* types based only on the scheme type.
*/

static bool scm_is_list_of_string_pairs (SCM val)
{
for (; !scm_is_null (val); val = scm_cdr (val))
{
if (!(scm_is_pair (val) && scm_is_pair (scm_car (val)) &&
scm_is_string (scm_caar (val))))
return false;
}
return true;
}

KvpValue *
gnc_scm_to_kvp_value_ptr(SCM val)
{
Expand Down Expand Up @@ -59,16 +71,31 @@ gnc_scm_to_kvp_value_ptr(SCM val)
{
return new KvpValue{gnc_scm_to_utf8_string(val)};
}
else if (SWIG_IsPointerOfType(val, SWIG_TypeQuery("_p_KvpFrame")))
else if (!scm_is_null (val) && scm_is_list_of_string_pairs (val))
{
auto frame = new KvpFrame;
for (; !scm_is_null (val); val = scm_cdr (val))
{
auto key_str = scm_to_utf8_stringn (scm_caar (val), nullptr);
auto val_scm = scm_cdar (val);
auto prev = frame->set ({key_str}, gnc_scm_to_kvp_value_ptr (val_scm));
g_free (key_str);
// there is a pre-existing key-value
if (prev)
delete prev;
}
return new KvpValue (frame);
}
else if (!scm_is_null (val) && scm_is_list (val))
{
#define FUNC_NAME G_STRFUNC
auto vp_frame = SWIG_MustGetPtr(val,
SWIG_TypeQuery("_p_KvpFrame"), 1, 0);
KvpFrame *frame = static_cast<KvpFrame*>(vp_frame);
#undef FUNC_NAME
return new KvpValue{frame};
GList *kvplist = nullptr;
for (; !scm_is_null (val); val = scm_cdr (val))
{
auto elt = gnc_scm_to_kvp_value_ptr (scm_car (val));
kvplist = g_list_prepend (kvplist, elt);
}
return new KvpValue (g_list_reverse (kvplist));
}
/* FIXME: add list handler here */
return NULL;
}

Expand Down Expand Up @@ -102,12 +129,26 @@ gnc_kvp_value_ptr_to_scm(KvpValue* val)
break;
case KvpValue::Type::FRAME:
{
auto frame = val->get<KvpFrame*>();
if (frame != nullptr)
return SWIG_NewPointerObj(frame, SWIG_TypeQuery("_p_KvpFrame"), 0);
auto frame { val->get<KvpFrame*>() };
auto acc = [](const auto& rv, const auto& iter)
{
auto key_scm { scm_from_utf8_string (iter.first) };
auto val_scm { gnc_kvp_value_ptr_to_scm (iter.second) };
return scm_acons (key_scm, val_scm, rv);
};
return scm_reverse (std::accumulate (frame->begin(), frame->end(), SCM_EOL, acc));
}
break;
case KvpValue::Type::GLIST:
{
SCM lst = SCM_EOL;
for (GList *n = val->get<GList*>(); n; n = n->next)
{
auto elt = gnc_kvp_value_ptr_to_scm (static_cast<KvpValue*>(n->data));
lst = scm_cons (elt, lst);
}
return scm_reverse (lst);
}
default:
break;
}
Expand Down
1 change: 1 addition & 0 deletions bindings/guile/test/CMakeLists.txt
Expand Up @@ -61,6 +61,7 @@ set (scm_tests_with_srfi64_SOURCES
test-core-utils.scm
test-business-core.scm
test-scm-engine.scm
test-scm-kvpvalue.scm
)

if (HAVE_SRFI64)
Expand Down
68 changes: 68 additions & 0 deletions bindings/guile/test/test-scm-kvpvalue.scm
@@ -0,0 +1,68 @@
(use-modules (srfi srfi-64))
(use-modules (tests srfi64-extras))
(use-modules (gnucash engine))
(use-modules (gnucash app-utils))

(define (run-test)
(test-runner-factory gnc:test-runner)
(test-begin "test-app-utils")
(test-kvp-access)
(test-end "test-app-utils"))

(define (setup book)
(qof-book-set-option book "bla" '("top" "lvl1a"))
(qof-book-set-option book "arg" '("top" "lvl1b"))
(qof-book-set-option book "baf" '("top" "lvl1c" "lvl2" "lvl3")))

(define (teardown)
(gnc-clear-current-session))

(define (test-kvp-access)
(define book (gnc-get-current-book))
(test-begin "kvp-access from guile")

(setup book)

(test-equal "top/lvl1a"
"bla"
(qof-book-get-option book '("top" "lvl1a")))

(test-equal "top/lvl1b"
"arg"
(qof-book-get-option book '("top" "lvl1b")))

(test-equal "top/lvl1c/lvl2/lvl3"
"baf"
(qof-book-get-option book '("top" "lvl1c" "lvl2" "lvl3")))

(test-equal "top/lvl1c/lvl2"
'(("lvl3" . "baf"))
(qof-book-get-option book '("top" "lvl1c" "lvl2")))

(test-equal "top/lvl1c"
'(("lvl2" ("lvl3" . "baf")))
(qof-book-get-option book '("top" "lvl1c")))

;; this tests the reading & writing of KvpFrame, copying branch
;; from top/lvl1c to top/lvl1d
(qof-book-set-option book
(qof-book-get-option book '("top" "lvl1c"))
'("top" "lvl1d"))

(test-equal "top/lvl1d, after copying from top/lvl1c"
'(("lvl2" ("lvl3" . "baf")))
(qof-book-get-option book '("top" "lvl1d")))

(test-equal "top/lvl1c/lvl2/error"
#f
(qof-book-get-option book '("top" "lvl1c" "lvl2" "error")))

(test-equal "top"
'(("lvl1a" . "bla")
("lvl1b" . "arg")
("lvl1c" ("lvl2" ("lvl3" . "baf")))
("lvl1d" ("lvl2" ("lvl3" . "baf"))))
(qof-book-get-option book '("top")))

(test-end "kvp-access from guile")
(teardown))
2 changes: 2 additions & 0 deletions libgnucash/engine/kvp-frame.cpp
Expand Up @@ -78,6 +78,8 @@ KvpFrame::get_child_frame_or_nullptr (Path const & path) noexcept
if (map_iter == m_valuemap.end ())
return nullptr;
auto child = map_iter->second->get <KvpFrame *> ();
if (!child)
return nullptr;
Path send;
std::copy (path.begin () + 1, path.end (), std::back_inserter (send));
return child->get_child_frame_or_nullptr (send);
Expand Down
3 changes: 3 additions & 0 deletions libgnucash/engine/kvp-frame.hpp
Expand Up @@ -226,6 +226,9 @@ struct KvpFrameImpl
bool empty() const noexcept { return m_valuemap.empty(); }
friend int compare(const KvpFrameImpl&, const KvpFrameImpl&) noexcept;

map_type::iterator begin() { return m_valuemap.begin(); }
map_type::iterator end() { return m_valuemap.end(); }

private:
map_type m_valuemap;

Expand Down

0 comments on commit d022651

Please sign in to comment.