diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj
index 92c1adda74..bc089866bb 100644
--- a/Builds/VisualStudio2013/RippleD.vcxproj
+++ b/Builds/VisualStudio2013/RippleD.vcxproj
@@ -3341,6 +3341,8 @@
+
+
@@ -3457,6 +3459,8 @@
+
+
diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters
index 9e451707c1..4cf6a31ca8 100644
--- a/Builds/VisualStudio2013/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters
@@ -4074,6 +4074,9 @@
ripple\test\jtx
+
+ ripple\test\jtx
+
ripple\test\jtx
@@ -4179,6 +4182,9 @@
ripple\test\jtx
+
+ ripple\test\jtx
+
ripple\test\jtx
diff --git a/src/ripple/test/jtx.h b/src/ripple/test/jtx.h
index f6ea000276..ed8ea395ed 100644
--- a/src/ripple/test/jtx.h
+++ b/src/ripple/test/jtx.h
@@ -37,6 +37,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/src/ripple/test/jtx/JTx.h b/src/ripple/test/jtx/JTx.h
index 1b3e9ad84a..b6dce761cb 100644
--- a/src/ripple/test/jtx/JTx.h
+++ b/src/ripple/test/jtx/JTx.h
@@ -21,9 +21,12 @@
#define RIPPLE_TEST_JTX_JTX_H_INCLUDED
#include
+#include
#include
#include
#include
+#include
+#include
namespace ripple {
namespace test {
@@ -46,6 +49,34 @@ struct JTx
JTx() = default;
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+ JTx(JTx&& src)
+ : jv(std::move(src.jv))
+ , fill_fee(std::move(src.fill_fee))
+ , fill_seq(std::move(src.fill_seq))
+ , fill_sig(std::move(src.fill_sig))
+ , signer(std::move(src.signer))
+ , requires(std::move(src.requires))
+ , ter(std::move(src.ter))
+ , props_(std::move(src.props_))
+ {
+ }
+
+ JTx& operator=(JTx&& src) noexcept
+ {
+ jv = std::move(src.jv);
+ fill_fee = std::move(src.fill_fee);
+ fill_seq = std::move(src.fill_seq);
+ fill_sig = std::move(src.fill_sig);
+ signer = std::move(src.signer);
+ requires = std::move(src.requires);
+ ter = std::move(src.ter);
+ props_ = std::move(src.props_);
+
+ return *this;
+ }
+#endif
+
JTx (Json::Value&& jv_)
: jv(std::move(jv_))
{
@@ -62,6 +93,115 @@ struct JTx
{
return jv[key];
}
+
+public:
+ /** Return a property if it exists
+
+ @return nullptr if the Prop does not exist
+ */
+ /** @{ */
+ template
+ Prop*
+ get()
+ {
+ for (auto& prop : props_.list)
+ {
+ if (auto test = dynamic_cast<
+ prop_type*>(
+ prop.get()))
+ return &test->t;
+ }
+ return nullptr;
+ }
+
+ template
+ Prop const*
+ get() const
+ {
+ for (auto& prop : props_.list)
+ {
+ if (auto test = dynamic_cast<
+ prop_type const*>(
+ prop.get()))
+ return &test->t;
+ }
+ return nullptr;
+ }
+ /** @} */
+
+ /** Set a property
+ If the property already exists,
+ it is replaced.
+ */
+ /** @{ */
+ void
+ set(std::unique_ptr p)
+ {
+ for (auto& prop : props_.list)
+ {
+ if (prop->assignable(p.get()))
+ {
+ prop = std::move(p);
+ return;
+ }
+ }
+ props_.list.emplace_back(std::move(p));
+ }
+
+ template
+ void
+ set(Args&&... args)
+ {
+ set(std::make_unique<
+ prop_type>(
+ std::forward (
+ args)...));
+ }
+ /** @} */
+
+private:
+ struct prop_list
+ {
+ prop_list() = default;
+
+ prop_list(prop_list const& src)
+ {
+ for (auto const& prop : src.list)
+ list.emplace_back(prop->clone());
+ }
+
+ prop_list& operator=(prop_list const& src)
+ {
+ if (this != &src)
+ {
+ list.clear();
+ for (auto const& prop : src.list)
+ list.emplace_back(prop->clone());
+ }
+ return *this;
+ }
+
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+ prop_list(prop_list&& src)
+ : list(std::move(src.list))
+ {
+ }
+
+ prop_list& operator=(prop_list&& src)
+ {
+ list = std::move(src.list);
+ return *this;
+ }
+#else
+ prop_list(prop_list&& src) = default;
+ prop_list& operator=(prop_list&& src) = default;
+#endif
+
+ std::vector> list;
+ };
+
+ prop_list props_;
};
} // jtx
diff --git a/src/ripple/test/jtx/basic_prop.h b/src/ripple/test/jtx/basic_prop.h
new file mode 100644
index 0000000000..bc994c5768
--- /dev/null
+++ b/src/ripple/test/jtx/basic_prop.h
@@ -0,0 +1,67 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2012, 2013 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef RIPPLE_TEST_JTX_BASIC_PROP_H_INCLUDED
+#define RIPPLE_TEST_JTX_BASIC_PROP_H_INCLUDED
+
+namespace ripple {
+namespace test {
+namespace jtx {
+
+struct basic_prop
+{
+ virtual ~basic_prop() = default;
+ virtual std::unique_ptr<
+ basic_prop> clone() const = 0;
+ virtual bool assignable(
+ basic_prop const*) const = 0;
+};
+
+template
+struct prop_type : basic_prop
+{
+ T t;
+
+ template
+ prop_type(Args&&... args)
+ : t(std::forward (args)...)
+ {
+ }
+
+ std::unique_ptr<
+ basic_prop> clone() const override
+ {
+ return std::make_unique<
+ prop_type>(t);
+ }
+
+ bool assignable(
+ basic_prop const* src) const override
+ {
+ return dynamic_cast<
+ prop_type const*>(
+ src);
+ }
+};
+
+} // jtx
+} // test
+} // ripple
+
+#endif
diff --git a/src/ripple/test/jtx/impl/Env.cpp b/src/ripple/test/jtx/impl/Env.cpp
index a4f5df61c5..5740edca42 100644
--- a/src/ripple/test/jtx/impl/Env.cpp
+++ b/src/ripple/test/jtx/impl/Env.cpp
@@ -239,7 +239,7 @@ Env::autofill_sig (JTx& jt)
auto const account =
lookup(jv[jss::Account].asString());
auto const ar = le(account);
- if (ar->isFieldPresent(sfRegularKey))
+ if (ar && ar->isFieldPresent(sfRegularKey))
jtx::sign(jv, lookup(
ar->getFieldAccount160(sfRegularKey)));
else
diff --git a/src/ripple/test/jtx/impl/Env_test.cpp b/src/ripple/test/jtx/impl/Env_test.cpp
index def29388be..98ed35ac13 100644
--- a/src/ripple/test/jtx/impl/Env_test.cpp
+++ b/src/ripple/test/jtx/impl/Env_test.cpp
@@ -414,6 +414,106 @@ public:
Env env(*this);
}
+ void testJTxProperties()
+ {
+ using namespace jtx;
+ JTx jt1;
+ // Test a straightforward
+ // property
+ expect(!jt1.get());
+ jt1.set(7);
+ expect(jt1.get());
+ expect(*jt1.get() == 7);
+ expect(!jt1.get());
+
+ // Test that the property is
+ // replaced if it exists.
+ jt1.set(17);
+ expect(jt1.get());
+ expect(*jt1.get() == 17);
+ expect(!jt1.get());
+
+ // Test that modifying the
+ // returned prop is saved
+ *jt1.get() = 42;
+ expect(jt1.get());
+ expect(*jt1.get() == 42);
+ expect(!jt1.get());
+
+ // Test get() const
+ auto const& jt2 = jt1;
+ expect(jt2.get());
+ expect(*jt2.get() == 42);
+ expect(!jt2.get());
+ }
+
+ void testProp()
+ {
+ using namespace jtx;
+ Env env(*this);
+ env.memoize("alice");
+
+ auto jt1 = env.jt(noop("alice"));
+ expect(!jt1.get());
+
+ auto jt2 = env.jt(noop("alice"),
+ prop(-1));
+ expect(jt2.get());
+ expect(*jt2.get() ==
+ 65535);
+
+ auto jt3 = env.jt(noop("alice"),
+ prop(
+ "Hello, world!"),
+ prop(false));
+ expect(jt3.get());
+ expect(*jt3.get() ==
+ "Hello, world!");
+ expect(jt3.get());
+ expect(!*jt3.get());
+ }
+
+ void testJTxCopy()
+ {
+ using namespace jtx;
+ JTx jt1;
+ jt1.set(7);
+ expect(jt1.get());
+ expect(*jt1.get() == 7);
+ expect(!jt1.get());
+ JTx jt2(jt1);
+ expect(jt2.get());
+ expect(*jt2.get() == 7);
+ expect(!jt2.get());
+ JTx jt3;
+ jt3 = jt1;
+ expect(jt3.get());
+ expect(*jt3.get() == 7);
+ expect(!jt3.get());
+ }
+
+ void testJTxMove()
+ {
+ using namespace jtx;
+ JTx jt1;
+ jt1.set(7);
+ expect(jt1.get());
+ expect(*jt1.get() == 7);
+ expect(!jt1.get());
+ JTx jt2(std::move(jt1));
+ expect(!jt1.get());
+ expect(!jt1.get());
+ expect(jt2.get());
+ expect(*jt2.get() == 7);
+ expect(!jt2.get());
+ jt1 = std::move(jt2);
+ expect(!jt2.get());
+ expect(!jt2.get());
+ expect(jt1.get());
+ expect(*jt1.get() == 7);
+ expect(!jt1.get());
+ }
+
void
testMemo()
{
@@ -447,6 +547,10 @@ public:
testMultiSign();
testMultiSign2();
testTicket();
+ testJTxProperties();
+ testProp();
+ testJTxCopy();
+ testJTxMove();
testMemo();
}
};
diff --git a/src/ripple/test/jtx/impl/utility.cpp b/src/ripple/test/jtx/impl/utility.cpp
index 722700951a..321571cc34 100644
--- a/src/ripple/test/jtx/impl/utility.cpp
+++ b/src/ripple/test/jtx/impl/utility.cpp
@@ -76,6 +76,9 @@ fill_seq (Json::Value& jv,
auto const ar = ledger.fetch(
getAccountRootIndex(ra.getAccountID()));
+ if (!ar)
+ return;
+
jv[jss::Sequence] =
ar->getFieldU32(sfSequence);
}
diff --git a/src/ripple/test/jtx/prop.h b/src/ripple/test/jtx/prop.h
new file mode 100644
index 0000000000..f5a7384e71
--- /dev/null
+++ b/src/ripple/test/jtx/prop.h
@@ -0,0 +1,56 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2012, 2013 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef RIPPLE_TEST_JTX_PROP_H_INCLUDED
+#define RIPPLE_TEST_JTX_PROP_H_INCLUDED
+
+#include
+#include //
+
+namespace ripple {
+namespace test {
+namespace jtx {
+
+/** Set a property on a JTx. */
+template
+struct prop
+{
+ std::unique_ptr p_;
+
+ template
+ prop(Args&&... args)
+ : p_(std::make_unique<
+ prop_type>(
+ std::forward (
+ args)...))
+ {
+ }
+
+ void
+ operator()(Env const& env, JTx& jt) const
+ {
+ jt.set(p_->clone());
+ }
+};
+
+} // jtx
+} // test
+} // ripple
+
+#endif