Make TypedValue constructor explicit for primitive types
Reviewers: mtomic, mferencevic, msantl Reviewed By: mtomic, msantl Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D2127
This commit is contained in:
parent
6d3e3ac4aa
commit
b3bc4d6809
@ -88,19 +88,19 @@ void Load(query::TypedValue *value, slk::Reader *reader,
|
||||
case static_cast<uint8_t>(1): {
|
||||
bool v;
|
||||
slk::Load(&v, reader);
|
||||
*value = v;
|
||||
*value = query::TypedValue(v);
|
||||
return;
|
||||
}
|
||||
case static_cast<uint8_t>(2): {
|
||||
int64_t v;
|
||||
slk::Load(&v, reader);
|
||||
*value = v;
|
||||
*value = query::TypedValue(v);
|
||||
return;
|
||||
}
|
||||
case static_cast<uint8_t>(3): {
|
||||
double v;
|
||||
slk::Load(&v, reader);
|
||||
*value = v;
|
||||
*value = query::TypedValue(v);
|
||||
return;
|
||||
}
|
||||
case static_cast<uint8_t>(4): {
|
||||
|
@ -120,17 +120,16 @@ TypedValue Size(TypedValue *args, int64_t nargs, const EvaluationContext &,
|
||||
case TypedValue::Type::Null:
|
||||
return TypedValue();
|
||||
case TypedValue::Type::List:
|
||||
return static_cast<int64_t>(
|
||||
args[0].ValueList().size());
|
||||
return TypedValue(static_cast<int64_t>(args[0].ValueList().size()));
|
||||
case TypedValue::Type::String:
|
||||
return static_cast<int64_t>(args[0].ValueString().size());
|
||||
return TypedValue(static_cast<int64_t>(args[0].ValueString().size()));
|
||||
case TypedValue::Type::Map:
|
||||
// neo4j doesn't implement size for map, but I don't see a good reason not
|
||||
// to do it.
|
||||
return static_cast<int64_t>(
|
||||
args[0].ValueMap().size());
|
||||
return TypedValue(static_cast<int64_t>(args[0].ValueMap().size()));
|
||||
case TypedValue::Type::Path:
|
||||
return static_cast<int64_t>(args[0].ValuePath().edges().size());
|
||||
return TypedValue(
|
||||
static_cast<int64_t>(args[0].ValuePath().edges().size()));
|
||||
default:
|
||||
throw QueryRuntimeException(
|
||||
"'size' argument must be a string, a collection or a path.");
|
||||
@ -162,7 +161,8 @@ TypedValue Degree(TypedValue *args, int64_t nargs, const EvaluationContext &,
|
||||
return TypedValue();
|
||||
case TypedValue::Type::Vertex: {
|
||||
auto &vertex = args[0].Value<VertexAccessor>();
|
||||
return static_cast<int64_t>(vertex.out_degree() + vertex.in_degree());
|
||||
return TypedValue(
|
||||
static_cast<int64_t>(vertex.out_degree() + vertex.in_degree()));
|
||||
}
|
||||
default:
|
||||
throw QueryRuntimeException("'degree' argument must be a node.");
|
||||
@ -180,7 +180,7 @@ TypedValue InDegree(TypedValue *args, int64_t nargs, const EvaluationContext &,
|
||||
return TypedValue();
|
||||
case TypedValue::Type::Vertex: {
|
||||
auto &vertex = args[0].Value<VertexAccessor>();
|
||||
return static_cast<int64_t>(vertex.in_degree());
|
||||
return TypedValue(static_cast<int64_t>(vertex.in_degree()));
|
||||
}
|
||||
default:
|
||||
throw QueryRuntimeException("'inDegree' argument must be a node.");
|
||||
@ -198,7 +198,7 @@ TypedValue OutDegree(TypedValue *args, int64_t nargs, const EvaluationContext &,
|
||||
return TypedValue();
|
||||
case TypedValue::Type::Vertex: {
|
||||
auto &vertex = args[0].Value<VertexAccessor>();
|
||||
return static_cast<int64_t>(vertex.out_degree());
|
||||
return TypedValue(static_cast<int64_t>(vertex.out_degree()));
|
||||
}
|
||||
default:
|
||||
throw QueryRuntimeException("'outDegree' argument must be a node.");
|
||||
@ -214,13 +214,13 @@ TypedValue ToBoolean(TypedValue *args, int64_t nargs, const EvaluationContext &,
|
||||
case TypedValue::Type::Null:
|
||||
return TypedValue();
|
||||
case TypedValue::Type::Bool:
|
||||
return args[0].Value<bool>();
|
||||
return TypedValue(args[0].Value<bool>());
|
||||
case TypedValue::Type::Int:
|
||||
return args[0].ValueInt() != 0L;
|
||||
return TypedValue(args[0].ValueInt() != 0L);
|
||||
case TypedValue::Type::String: {
|
||||
auto s = utils::ToUpperCase(utils::Trim(args[0].ValueString()));
|
||||
if (s == "TRUE") return true;
|
||||
if (s == "FALSE") return false;
|
||||
if (s == "TRUE") return TypedValue(true);
|
||||
if (s == "FALSE") return TypedValue(false);
|
||||
// I think this is just stupid and that exception should be thrown, but
|
||||
// neo4j does it this way...
|
||||
return TypedValue();
|
||||
@ -240,12 +240,13 @@ TypedValue ToFloat(TypedValue *args, int64_t nargs, const EvaluationContext &,
|
||||
case TypedValue::Type::Null:
|
||||
return TypedValue();
|
||||
case TypedValue::Type::Int:
|
||||
return static_cast<double>(args[0].Value<int64_t>());
|
||||
return TypedValue(static_cast<double>(args[0].Value<int64_t>()));
|
||||
case TypedValue::Type::Double:
|
||||
return args[0];
|
||||
case TypedValue::Type::String:
|
||||
try {
|
||||
return utils::ParseDouble(utils::Trim(args[0].ValueString()));
|
||||
return TypedValue(
|
||||
utils::ParseDouble(utils::Trim(args[0].ValueString())));
|
||||
} catch (const utils::BasicException &) {
|
||||
return TypedValue();
|
||||
}
|
||||
@ -264,17 +265,17 @@ TypedValue ToInteger(TypedValue *args, int64_t nargs, const EvaluationContext &,
|
||||
case TypedValue::Type::Null:
|
||||
return TypedValue();
|
||||
case TypedValue::Type::Bool:
|
||||
return args[0].ValueBool() ? 1L : 0L;
|
||||
return TypedValue(args[0].ValueBool() ? 1L : 0L);
|
||||
case TypedValue::Type::Int:
|
||||
return args[0];
|
||||
case TypedValue::Type::Double:
|
||||
return static_cast<int64_t>(args[0].Value<double>());
|
||||
return TypedValue(static_cast<int64_t>(args[0].Value<double>()));
|
||||
case TypedValue::Type::String:
|
||||
try {
|
||||
// Yup, this is correct. String is valid if it has floating point
|
||||
// number, then it is parsed and converted to int.
|
||||
return static_cast<int64_t>(
|
||||
utils::ParseDouble(utils::Trim(args[0].ValueString())));
|
||||
return TypedValue(static_cast<int64_t>(
|
||||
utils::ParseDouble(utils::Trim(args[0].ValueString()))));
|
||||
} catch (const utils::BasicException &) {
|
||||
return TypedValue();
|
||||
}
|
||||
@ -395,11 +396,11 @@ TypedValue Range(TypedValue *args, int64_t nargs, const EvaluationContext &,
|
||||
std::vector<TypedValue> list;
|
||||
if (lbound <= rbound && step > 0) {
|
||||
for (auto i = lbound; i <= rbound; i += step) {
|
||||
list.push_back(i);
|
||||
list.emplace_back(i);
|
||||
}
|
||||
} else if (lbound >= rbound && step < 0) {
|
||||
for (auto i = lbound; i >= rbound; i += step) {
|
||||
list.push_back(i);
|
||||
list.emplace_back(i);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
@ -471,10 +472,9 @@ TypedValue Abs(TypedValue *args, int64_t nargs, const EvaluationContext &,
|
||||
case TypedValue::Type::Null:
|
||||
return TypedValue();
|
||||
case TypedValue::Type::Int:
|
||||
return static_cast<int64_t>(
|
||||
std::abs(static_cast<long long>(args[0].Value<int64_t>())));
|
||||
return TypedValue(std::abs(args[0].Value<int64_t>()));
|
||||
case TypedValue::Type::Double:
|
||||
return std::abs(args[0].Value<double>());
|
||||
return TypedValue(std::abs(args[0].Value<double>()));
|
||||
default:
|
||||
throw QueryRuntimeException("'abs' argument should be a number.");
|
||||
}
|
||||
@ -491,9 +491,9 @@ TypedValue Abs(TypedValue *args, int64_t nargs, const EvaluationContext &,
|
||||
case TypedValue::Type::Null: \
|
||||
return TypedValue(); \
|
||||
case TypedValue::Type::Int: \
|
||||
return lowercased_name(args[0].Value<int64_t>()); \
|
||||
return TypedValue(lowercased_name(args[0].Value<int64_t>())); \
|
||||
case TypedValue::Type::Double: \
|
||||
return lowercased_name(args[0].Value<double>()); \
|
||||
return TypedValue(lowercased_name(args[0].Value<double>())); \
|
||||
default: \
|
||||
throw QueryRuntimeException(#lowercased_name \
|
||||
" argument must be a number."); \
|
||||
@ -537,7 +537,7 @@ TypedValue Atan2(TypedValue *args, int64_t nargs, const EvaluationContext &,
|
||||
};
|
||||
double y = to_double(args[0]);
|
||||
double x = to_double(args[1]);
|
||||
return atan2(y, x);
|
||||
return TypedValue(atan2(y, x));
|
||||
}
|
||||
|
||||
TypedValue Sign(TypedValue *args, int64_t nargs, const EvaluationContext &,
|
||||
@ -545,7 +545,7 @@ TypedValue Sign(TypedValue *args, int64_t nargs, const EvaluationContext &,
|
||||
if (nargs != 1) {
|
||||
throw QueryRuntimeException("'sign' requires exactly one argument.");
|
||||
}
|
||||
auto sign = [](auto x) { return (0 < x) - (x < 0); };
|
||||
auto sign = [](auto x) { return TypedValue((0 < x) - (x < 0)); };
|
||||
switch (args[0].type()) {
|
||||
case TypedValue::Type::Null:
|
||||
return TypedValue();
|
||||
@ -563,7 +563,7 @@ TypedValue E(TypedValue *, int64_t nargs, const EvaluationContext &,
|
||||
if (nargs != 0) {
|
||||
throw QueryRuntimeException("'e' requires no arguments.");
|
||||
}
|
||||
return M_E;
|
||||
return TypedValue(M_E);
|
||||
}
|
||||
|
||||
TypedValue Pi(TypedValue *, int64_t nargs, const EvaluationContext &,
|
||||
@ -571,7 +571,7 @@ TypedValue Pi(TypedValue *, int64_t nargs, const EvaluationContext &,
|
||||
if (nargs != 0) {
|
||||
throw QueryRuntimeException("'pi' requires no arguments.");
|
||||
}
|
||||
return M_PI;
|
||||
return TypedValue(M_PI);
|
||||
}
|
||||
|
||||
TypedValue Rand(TypedValue *, int64_t nargs, const EvaluationContext &,
|
||||
@ -581,7 +581,7 @@ TypedValue Rand(TypedValue *, int64_t nargs, const EvaluationContext &,
|
||||
if (nargs != 0) {
|
||||
throw QueryRuntimeException("'rand' requires no arguments.");
|
||||
}
|
||||
return rand_dist_(pseudo_rand_gen_);
|
||||
return TypedValue(rand_dist_(pseudo_rand_gen_));
|
||||
}
|
||||
|
||||
template <bool (*Predicate)(const TypedValue::TString &s1,
|
||||
@ -607,7 +607,7 @@ TypedValue StringMatchOperator(TypedValue *args, int64_t nargs,
|
||||
if (has_null) return TypedValue();
|
||||
const auto &s1 = args[0].ValueString();
|
||||
const auto &s2 = args[1].ValueString();
|
||||
return Predicate(s1, s2);
|
||||
return TypedValue(Predicate(s1, s2));
|
||||
}
|
||||
|
||||
// Check if s1 starts with s2.
|
||||
@ -682,7 +682,7 @@ TypedValue Counter(TypedValue *args, int64_t nargs,
|
||||
auto value = it->second;
|
||||
it->second += step;
|
||||
|
||||
return value;
|
||||
return TypedValue(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -695,9 +695,9 @@ TypedValue WorkerId(TypedValue *args, int64_t nargs, const EvaluationContext &,
|
||||
auto &arg = args[0];
|
||||
switch (arg.type()) {
|
||||
case TypedValue::Type::Vertex:
|
||||
return arg.ValueVertex().GlobalAddress().worker_id();
|
||||
return TypedValue(arg.ValueVertex().GlobalAddress().worker_id());
|
||||
case TypedValue::Type::Edge:
|
||||
return arg.ValueEdge().GlobalAddress().worker_id();
|
||||
return TypedValue(arg.ValueEdge().GlobalAddress().worker_id());
|
||||
default:
|
||||
throw QueryRuntimeException(
|
||||
"'workerId' argument must be a node or an edge.");
|
||||
@ -739,7 +739,7 @@ TypedValue ToString(TypedValue *args, int64_t nargs, const EvaluationContext &,
|
||||
case TypedValue::Type::Double:
|
||||
return std::to_string(arg.ValueDouble());
|
||||
case TypedValue::Type::Bool:
|
||||
return arg.ValueBool() ? "true" : "false";
|
||||
return TypedValue(arg.ValueBool() ? "true" : "false");
|
||||
default:
|
||||
throw QueryRuntimeException(
|
||||
"'toString' argument must be a number, a string or a boolean.");
|
||||
@ -751,7 +751,7 @@ TypedValue Timestamp(TypedValue *, int64_t nargs, const EvaluationContext &ctx,
|
||||
if (nargs != 0) {
|
||||
throw QueryRuntimeException("'timestamp' requires no arguments.");
|
||||
}
|
||||
return ctx.timestamp;
|
||||
return TypedValue(ctx.timestamp);
|
||||
}
|
||||
|
||||
TypedValue Left(TypedValue *args, int64_t nargs, const EvaluationContext &,
|
||||
|
@ -137,7 +137,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
// element in the list since result of every comparison will be NULL. There
|
||||
// is one special case that we must test explicitly: if list is empty then
|
||||
// result is false since no comparison will be performed.
|
||||
if (list.size() == 0U) return false;
|
||||
if (list.empty()) return TypedValue(false);
|
||||
if (literal.IsNull()) return TypedValue();
|
||||
|
||||
auto has_null = false;
|
||||
@ -146,13 +146,13 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
if (result.IsNull()) {
|
||||
has_null = true;
|
||||
} else if (result.Value<bool>()) {
|
||||
return true;
|
||||
return TypedValue(true);
|
||||
}
|
||||
}
|
||||
if (has_null) {
|
||||
return TypedValue();
|
||||
}
|
||||
return false;
|
||||
return TypedValue(false);
|
||||
}
|
||||
|
||||
TypedValue Visit(SubscriptOperator &list_indexing) override {
|
||||
@ -261,7 +261,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
|
||||
TypedValue Visit(IsNullOperator &is_null) override {
|
||||
auto value = is_null.expression_->Accept(*this);
|
||||
return value.IsNull();
|
||||
return TypedValue(value.IsNull());
|
||||
}
|
||||
|
||||
TypedValue Visit(PropertyLookup &property_lookup) override {
|
||||
@ -296,10 +296,10 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
auto vertex = expression_result.Value<VertexAccessor>();
|
||||
for (const auto label : labels_test.labels_) {
|
||||
if (!vertex.has_label(GetLabel(label))) {
|
||||
return false;
|
||||
return TypedValue(false);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return TypedValue(true);
|
||||
}
|
||||
default:
|
||||
throw QueryRuntimeException("Only nodes have labels.");
|
||||
@ -440,7 +440,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return TypedValue(true);
|
||||
}
|
||||
|
||||
TypedValue Visit(Single &single) override {
|
||||
@ -468,12 +468,12 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
}
|
||||
// Return false if more than one element satisfies the predicate.
|
||||
if (predicate_satisfied) {
|
||||
return false;
|
||||
return TypedValue(false);
|
||||
} else {
|
||||
predicate_satisfied = true;
|
||||
}
|
||||
}
|
||||
return predicate_satisfied;
|
||||
return TypedValue(predicate_satisfied);
|
||||
}
|
||||
|
||||
TypedValue Visit(ParameterLookup ¶m_lookup) override {
|
||||
@ -500,7 +500,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
const auto &target_string = target_string_value.ValueString();
|
||||
try {
|
||||
std::regex regex(regex_value.ValueString());
|
||||
return std::regex_match(target_string, regex);
|
||||
return TypedValue(std::regex_match(target_string, regex));
|
||||
} catch (const std::regex_error &e) {
|
||||
throw QueryRuntimeException("Regex error in '{}': {}",
|
||||
regex_value.ValueString(), e.what());
|
||||
|
@ -674,7 +674,7 @@ Callback HandleInfoQuery(InfoQuery *info_query,
|
||||
return db_accessor->PropertyName(p);
|
||||
});
|
||||
|
||||
std::vector<TypedValue> constraint{"unique",
|
||||
std::vector<TypedValue> constraint{TypedValue("unique"),
|
||||
db_accessor->LabelName(e.label),
|
||||
utils::Join(property_names, ",")};
|
||||
|
||||
@ -691,8 +691,10 @@ Callback HandleInfoQuery(InfoQuery *info_query,
|
||||
callback.header = {"info", "value"};
|
||||
callback.fn = [db_accessor] {
|
||||
std::vector<std::vector<TypedValue>> results(
|
||||
{{"is_leader", db_accessor->raft()->IsLeader()},
|
||||
{"term_id", static_cast<int64_t>(db_accessor->raft()->TermId())}});
|
||||
{{TypedValue("is_leader"),
|
||||
TypedValue(db_accessor->raft()->IsLeader())},
|
||||
{TypedValue("term_id"), TypedValue(static_cast<int64_t>(
|
||||
db_accessor->raft()->TermId()))}});
|
||||
return results;
|
||||
};
|
||||
// It is critical to abort this query because it can be executed on
|
||||
|
@ -1398,12 +1398,12 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
|
||||
throw QueryRuntimeException(
|
||||
"Calculated weight must be numeric, got {}.", typed_weight.type());
|
||||
}
|
||||
if ((typed_weight < 0).Value<bool>()) {
|
||||
if ((typed_weight < TypedValue(0)).Value<bool>()) {
|
||||
throw QueryRuntimeException("Calculated weight must be non-negative!");
|
||||
}
|
||||
|
||||
auto next_state = create_state(vertex, depth);
|
||||
auto next_weight = weight + typed_weight;
|
||||
auto next_weight = TypedValue(weight) + typed_weight;
|
||||
auto found_it = total_cost_.find(next_state);
|
||||
if (found_it != total_cost_.end() &&
|
||||
found_it->second.Value<double>() <= next_weight.Value<double>())
|
||||
@ -2520,7 +2520,8 @@ class AggregateCursor : public Cursor {
|
||||
AggregationValue &agg_value = kv.second;
|
||||
int count = agg_value.counts_[pos];
|
||||
if (count > 0)
|
||||
agg_value.values_[pos] = agg_value.values_[pos] / (double)count;
|
||||
agg_value.values_[pos] =
|
||||
agg_value.values_[pos] / TypedValue(static_cast<double>(count));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,8 +52,9 @@ class ProfilingStatsToTableHelper {
|
||||
auto cycles = IndividualCycles(cumulative_stats);
|
||||
|
||||
rows_.emplace_back(std::vector<TypedValue>{
|
||||
FormatOperator(cumulative_stats.name), cumulative_stats.actual_hits,
|
||||
FormatRelativeTime(cycles), FormatAbsoluteTime(cycles)});
|
||||
FormatOperator(cumulative_stats.name),
|
||||
TypedValue(cumulative_stats.actual_hits), FormatRelativeTime(cycles),
|
||||
FormatAbsoluteTime(cycles)});
|
||||
|
||||
for (size_t i = 1; i < cumulative_stats.children.size(); ++i) {
|
||||
Branch(cumulative_stats.children[i]);
|
||||
@ -68,7 +69,8 @@ class ProfilingStatsToTableHelper {
|
||||
|
||||
private:
|
||||
void Branch(const ProfilingStats &cumulative_stats) {
|
||||
rows_.emplace_back(std::vector<TypedValue>{"|\\", "", "", ""});
|
||||
rows_.emplace_back(std::vector<TypedValue>{
|
||||
TypedValue("|\\"), TypedValue(""), TypedValue(""), TypedValue("")});
|
||||
|
||||
++depth_;
|
||||
Output(cumulative_stats);
|
||||
|
@ -121,27 +121,26 @@ class TypedValue {
|
||||
*/
|
||||
TypedValue(TypedValue &&other, utils::MemoryResource *memory);
|
||||
|
||||
// constructors for primitive types
|
||||
TypedValue(bool value,
|
||||
utils::MemoryResource *memory = utils::NewDeleteResource())
|
||||
explicit TypedValue(
|
||||
bool value, utils::MemoryResource *memory = utils::NewDeleteResource())
|
||||
: memory_(memory), type_(Type::Bool) {
|
||||
bool_v = value;
|
||||
}
|
||||
|
||||
TypedValue(int value,
|
||||
utils::MemoryResource *memory = utils::NewDeleteResource())
|
||||
explicit TypedValue(
|
||||
int value, utils::MemoryResource *memory = utils::NewDeleteResource())
|
||||
: memory_(memory), type_(Type::Int) {
|
||||
int_v = value;
|
||||
}
|
||||
|
||||
TypedValue(int64_t value,
|
||||
utils::MemoryResource *memory = utils::NewDeleteResource())
|
||||
explicit TypedValue(
|
||||
int64_t value, utils::MemoryResource *memory = utils::NewDeleteResource())
|
||||
: memory_(memory), type_(Type::Int) {
|
||||
int_v = value;
|
||||
}
|
||||
|
||||
TypedValue(double value,
|
||||
utils::MemoryResource *memory = utils::NewDeleteResource())
|
||||
explicit TypedValue(
|
||||
double value, utils::MemoryResource *memory = utils::NewDeleteResource())
|
||||
: memory_(memory), type_(Type::Double) {
|
||||
double_v = value;
|
||||
}
|
||||
@ -156,8 +155,8 @@ class TypedValue {
|
||||
new (&string_v) TString(value, memory_);
|
||||
}
|
||||
|
||||
TypedValue(const char *value,
|
||||
utils::MemoryResource *memory = utils::NewDeleteResource())
|
||||
explicit TypedValue(const char *value, utils::MemoryResource *memory =
|
||||
utils::NewDeleteResource())
|
||||
: memory_(memory), type_(Type::String) {
|
||||
new (&string_v) TString(value, memory_);
|
||||
}
|
||||
|
@ -326,7 +326,7 @@ static void Aggregate(benchmark::State &state) {
|
||||
evaluation_context};
|
||||
TMemory memory;
|
||||
auto cursor = aggregate.MakeCursor(&dba, memory.get());
|
||||
frame[symbols.front()] = 0; // initial group_by value
|
||||
frame[symbols.front()] = query::TypedValue(0); // initial group_by value
|
||||
while (cursor->Pull(frame, execution_context))
|
||||
frame[symbols.front()].ValueInt()++; // new group_by value
|
||||
}
|
||||
|
@ -27,10 +27,10 @@ int main(int argc, char *argv[]) {
|
||||
cluster.Execute("UNWIND range(0, $pos_count) AS id CREATE (:Pos {id:id})",
|
||||
{{"pos_count", kPosCount - 1}});
|
||||
|
||||
CheckResults(cluster.Execute("MATCH (:Pos) RETURN count(1)"), {{kPosCount}},
|
||||
"Failed to create POS");
|
||||
CheckResults(cluster.Execute("MATCH (:Card) RETURN count(1)"), {{kCardCount}},
|
||||
"Failed to create Cards");
|
||||
CheckResults(cluster.Execute("MATCH (:Pos) RETURN count(1)"),
|
||||
{{query::TypedValue(kPosCount)}}, "Failed to create POS");
|
||||
CheckResults(cluster.Execute("MATCH (:Card) RETURN count(1)"),
|
||||
{{query::TypedValue(kCardCount)}}, "Failed to create Cards");
|
||||
|
||||
std::atomic<int> tx_counter{0};
|
||||
auto create_tx = [&cluster, kCardCount, kPosCount, &tx_counter](int count) {
|
||||
@ -50,7 +50,7 @@ int main(int argc, char *argv[]) {
|
||||
{{"pos", rint(kPosCount)},
|
||||
{"card", rint(kCardCount)},
|
||||
{"tx", tx_counter++}});
|
||||
CheckResults(res, {{1}}, "Transaction creation");
|
||||
CheckResults(res, {{query::TypedValue(1)}}, "Transaction creation");
|
||||
} catch (utils::LockTimeoutException &) {
|
||||
--i;
|
||||
} catch (mvcc::SerializationError &) {
|
||||
@ -68,9 +68,10 @@ int main(int argc, char *argv[]) {
|
||||
tx_creators.emplace_back(create_tx, FLAGS_tx_per_thread);
|
||||
for (auto &t : tx_creators) t.join();
|
||||
|
||||
CheckResults(cluster.Execute("MATCH (:Transaction) RETURN count(1)"),
|
||||
{{FLAGS_num_tx_creators * FLAGS_tx_per_thread}},
|
||||
"Failed to create Transactions");
|
||||
CheckResults(
|
||||
cluster.Execute("MATCH (:Transaction) RETURN count(1)"),
|
||||
{{query::TypedValue(FLAGS_num_tx_creators * FLAGS_tx_per_thread)}},
|
||||
"Failed to create Transactions");
|
||||
|
||||
LOG(INFO) << "Test terminated successfully";
|
||||
return 0;
|
||||
|
@ -54,10 +54,13 @@ class Base {
|
||||
}
|
||||
}
|
||||
|
||||
void CheckLiteral(Expression *expression, const TypedValue &expected,
|
||||
template <class TValue>
|
||||
void CheckLiteral(Expression *expression, const TValue &expected,
|
||||
const std::optional<int> &token_position = std::nullopt) {
|
||||
TypedValue value;
|
||||
if (!expected.IsNull() && context_.is_query_cached) {
|
||||
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
|
||||
TypedValue expected_tv(expected);
|
||||
if (!expected_tv.IsNull() && context_.is_query_cached) {
|
||||
auto *param_lookup = dynamic_cast<ParameterLookup *>(expression);
|
||||
ASSERT_TRUE(param_lookup);
|
||||
if (token_position)
|
||||
@ -69,7 +72,7 @@ class Base {
|
||||
if (token_position) ASSERT_EQ(literal->token_position_, *token_position);
|
||||
value = literal->value_;
|
||||
}
|
||||
EXPECT_TRUE(TypedValue::BoolEqual{}(value, expected));
|
||||
EXPECT_TRUE(TypedValue::BoolEqual{}(value, expected_tv));
|
||||
}
|
||||
};
|
||||
|
||||
@ -2076,13 +2079,14 @@ TEST_P(CypherMainVisitorTest, CreateUser) {
|
||||
check_auth_query(&ast_generator, "CREATE USER user",
|
||||
AuthQuery::Action::CREATE_USER, "user", "", "", {}, {});
|
||||
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY 'password'",
|
||||
AuthQuery::Action::CREATE_USER, "user", "", "", "password",
|
||||
{});
|
||||
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY ''",
|
||||
AuthQuery::Action::CREATE_USER, "user", "", "", "", {});
|
||||
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY null",
|
||||
AuthQuery::Action::CREATE_USER, "user", "", "",
|
||||
TypedValue(), {});
|
||||
TypedValue("password"), {});
|
||||
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY ''",
|
||||
AuthQuery::Action::CREATE_USER, "user", "", "",
|
||||
TypedValue(""), {});
|
||||
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY null",
|
||||
AuthQuery::Action::CREATE_USER, "user", "", "", TypedValue(),
|
||||
{});
|
||||
ASSERT_THROW(
|
||||
ast_generator.ParseQuery("CRATE USER user IDENTIFIED BY password"),
|
||||
SyntaxException);
|
||||
@ -2101,8 +2105,8 @@ TEST_P(CypherMainVisitorTest, SetPassword) {
|
||||
AuthQuery::Action::SET_PASSWORD, "user", "", "",
|
||||
TypedValue(), {});
|
||||
check_auth_query(&ast_generator, "SET PASSWORD FOR user TO 'password'",
|
||||
AuthQuery::Action::SET_PASSWORD, "user", "", "", "password",
|
||||
{});
|
||||
AuthQuery::Action::SET_PASSWORD, "user", "", "",
|
||||
TypedValue("password"), {});
|
||||
ASSERT_THROW(ast_generator.ParseQuery("SET PASSWORD FOR user To 5"),
|
||||
SyntaxException);
|
||||
}
|
||||
|
@ -50,10 +50,13 @@ class Base {
|
||||
}
|
||||
}
|
||||
|
||||
void CheckLiteral(Expression *expression, const TypedValue &expected,
|
||||
template <class TValue>
|
||||
void CheckLiteral(Expression *expression, const TValue &expected,
|
||||
const std::optional<int> &token_position = std::nullopt) {
|
||||
TypedValue value;
|
||||
if (!expected.IsNull() && context_.is_query_cached) {
|
||||
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
|
||||
TypedValue expected_tv(expected);
|
||||
if (!expected_tv.IsNull() && context_.is_query_cached) {
|
||||
auto *param_lookup = dynamic_cast<ParameterLookup *>(expression);
|
||||
ASSERT_TRUE(param_lookup);
|
||||
if (token_position)
|
||||
@ -65,7 +68,7 @@ class Base {
|
||||
if (token_position) ASSERT_EQ(literal->token_position_, *token_position);
|
||||
value = literal->value_;
|
||||
}
|
||||
EXPECT_TRUE(TypedValue::BoolEqual{}(value, expected));
|
||||
EXPECT_TRUE(TypedValue::BoolEqual{}(value, expected_tv));
|
||||
}
|
||||
};
|
||||
|
||||
@ -2180,13 +2183,14 @@ TEST_P(CypherMainVisitorTest, CreateUser) {
|
||||
check_auth_query(&ast_generator, "CREATE USER user",
|
||||
AuthQuery::Action::CREATE_USER, "user", "", "", {}, {});
|
||||
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY 'password'",
|
||||
AuthQuery::Action::CREATE_USER, "user", "", "", "password",
|
||||
{});
|
||||
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY ''",
|
||||
AuthQuery::Action::CREATE_USER, "user", "", "", "", {});
|
||||
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY null",
|
||||
AuthQuery::Action::CREATE_USER, "user", "", "",
|
||||
TypedValue(), {});
|
||||
TypedValue("password"), {});
|
||||
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY ''",
|
||||
AuthQuery::Action::CREATE_USER, "user", "", "",
|
||||
TypedValue(""), {});
|
||||
check_auth_query(&ast_generator, "CREATE USER user IDENTIFIED BY null",
|
||||
AuthQuery::Action::CREATE_USER, "user", "", "", TypedValue(),
|
||||
{});
|
||||
ASSERT_THROW(
|
||||
ast_generator.ParseQuery("CRATE USER user IDENTIFIED BY password"),
|
||||
SyntaxException);
|
||||
@ -2205,8 +2209,8 @@ TEST_P(CypherMainVisitorTest, SetPassword) {
|
||||
AuthQuery::Action::SET_PASSWORD, "user", "", "",
|
||||
TypedValue(), {});
|
||||
check_auth_query(&ast_generator, "SET PASSWORD FOR user TO 'password'",
|
||||
AuthQuery::Action::SET_PASSWORD, "user", "", "", "password",
|
||||
{});
|
||||
AuthQuery::Action::SET_PASSWORD, "user", "", "",
|
||||
TypedValue("password"), {});
|
||||
ASSERT_THROW(ast_generator.ParseQuery("SET PASSWORD FOR user To 5"),
|
||||
SyntaxException);
|
||||
}
|
||||
|
@ -343,7 +343,7 @@ TEST_F(DistributedQueryPlan, PullRemoteOrderBy) {
|
||||
|
||||
ASSERT_EQ(results.size(), 300);
|
||||
for (int j = 0; j < 300; ++j) {
|
||||
EXPECT_TRUE(TypedValue::BoolEqual{}(results[j][0], j));
|
||||
EXPECT_TRUE(TypedValue::BoolEqual{}(results[j][0], TypedValue(j)));
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -591,13 +591,13 @@ TEST(QueryPlan, Unwind) {
|
||||
ASSERT_EQ(4, results.size());
|
||||
const std::vector<int> expected_x_card{3, 3, 3, 1};
|
||||
auto expected_x_card_it = expected_x_card.begin();
|
||||
const std::vector<TypedValue> expected_y{1, true, "x", "bla"};
|
||||
const std::vector<TypedValue> expected_y{TypedValue(1), TypedValue(true),
|
||||
TypedValue("x"), TypedValue("bla")};
|
||||
auto expected_y_it = expected_y.begin();
|
||||
for (const auto &row : results) {
|
||||
ASSERT_EQ(2, row.size());
|
||||
ASSERT_EQ(row[0].type(), TypedValue::Type::List);
|
||||
EXPECT_EQ(row[0].ValueList().size(),
|
||||
*expected_x_card_it);
|
||||
EXPECT_EQ(row[0].ValueList().size(), *expected_x_card_it);
|
||||
EXPECT_EQ(row[1].type(), expected_y_it->type());
|
||||
expected_x_card_it++;
|
||||
expected_y_it++;
|
||||
|
@ -1542,11 +1542,20 @@ TEST(QueryPlan, Distinct) {
|
||||
}
|
||||
};
|
||||
|
||||
check_distinct({1, 1, 2, 3, 3, 3}, {1, 2, 3}, true);
|
||||
check_distinct({3, 2, 3, 5, 3, 5, 2, 1, 2}, {3, 2, 5, 1}, true);
|
||||
check_distinct({TypedValue(1), TypedValue(1), TypedValue(2), TypedValue(3),
|
||||
TypedValue(3), TypedValue(3)},
|
||||
{TypedValue(1), TypedValue(2), TypedValue(3)}, true);
|
||||
check_distinct({TypedValue(3), TypedValue(2), TypedValue(3), TypedValue(5),
|
||||
TypedValue(3), TypedValue(5), TypedValue(2), TypedValue(1),
|
||||
TypedValue(2)},
|
||||
{TypedValue(3), TypedValue(2), TypedValue(5), TypedValue(1)},
|
||||
true);
|
||||
check_distinct(
|
||||
{3, "two", TypedValue(), 3, true, false, "TWO", TypedValue()},
|
||||
{3, "two", TypedValue(), true, false, "TWO"}, false);
|
||||
{TypedValue(3), TypedValue("two"), TypedValue(), TypedValue(3),
|
||||
TypedValue(true), TypedValue(false), TypedValue("TWO"), TypedValue()},
|
||||
{TypedValue(3), TypedValue("two"), TypedValue(), TypedValue(true),
|
||||
TypedValue(false), TypedValue("TWO")},
|
||||
false);
|
||||
}
|
||||
|
||||
TEST(QueryPlan, ScanAllByLabel) {
|
||||
@ -1625,14 +1634,20 @@ TEST(QueryPlan, ScanAllByLabelProperty) {
|
||||
};
|
||||
|
||||
// normal ranges that return something
|
||||
check(false, Bound::Type::INCLUSIVE, true, Bound::Type::EXCLUSIVE, {false});
|
||||
check(false, Bound::Type::EXCLUSIVE, true, Bound::Type::INCLUSIVE, {true});
|
||||
check("a", Bound::Type::EXCLUSIVE, "c", Bound::Type::EXCLUSIVE, {"b"});
|
||||
check(0, Bound::Type::EXCLUSIVE, 2, Bound::Type::INCLUSIVE, {0.5, 1, 1.5, 2});
|
||||
check(1.5, Bound::Type::EXCLUSIVE, 2.5, Bound::Type::INCLUSIVE, {2, 2.5});
|
||||
check(std::vector<TypedValue>{0.5}, Bound::Type::EXCLUSIVE,
|
||||
std::vector<TypedValue>{1.5}, Bound::Type::INCLUSIVE,
|
||||
{TypedValue(std::vector<TypedValue>{1})});
|
||||
check(TypedValue(false), Bound::Type::INCLUSIVE, TypedValue(true),
|
||||
Bound::Type::EXCLUSIVE, {TypedValue(false)});
|
||||
check(TypedValue(false), Bound::Type::EXCLUSIVE, TypedValue(true),
|
||||
Bound::Type::INCLUSIVE, {TypedValue(true)});
|
||||
check(TypedValue("a"), Bound::Type::EXCLUSIVE, TypedValue("c"),
|
||||
Bound::Type::EXCLUSIVE, {TypedValue("b")});
|
||||
check(TypedValue(0), Bound::Type::EXCLUSIVE, TypedValue(2),
|
||||
Bound::Type::INCLUSIVE,
|
||||
{TypedValue(0.5), TypedValue(1), TypedValue(1.5), TypedValue(2)});
|
||||
check(TypedValue(1.5), Bound::Type::EXCLUSIVE, TypedValue(2.5),
|
||||
Bound::Type::INCLUSIVE, {TypedValue(2), TypedValue(2.5)});
|
||||
check(std::vector<TypedValue>{TypedValue(0.5)}, Bound::Type::EXCLUSIVE,
|
||||
std::vector<TypedValue>{TypedValue(1.5)}, Bound::Type::INCLUSIVE,
|
||||
{TypedValue(std::vector<TypedValue>{TypedValue(1)})});
|
||||
|
||||
// when a range contains different types, nothing should get returned
|
||||
for (const auto &value_a : values)
|
||||
@ -1682,7 +1697,7 @@ TEST(QueryPlan, ScanAllByLabelPropertyEqualityNoError) {
|
||||
auto vertex = row[0].Value<VertexAccessor>();
|
||||
auto value = vertex.PropsAt(prop);
|
||||
TypedValue::BoolEqual eq;
|
||||
EXPECT_TRUE(eq(value, 42));
|
||||
EXPECT_TRUE(eq(value, TypedValue(42)));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, ScanAllByLabelPropertyValueError) {
|
||||
|
@ -28,17 +28,17 @@ class AllTypesFixture : public testing::Test {
|
||||
values_.emplace_back(3.14);
|
||||
values_.emplace_back("something");
|
||||
values_.emplace_back(
|
||||
std::vector<TypedValue>{true, "something", 42, 0.5, TypedValue()});
|
||||
std::vector<TypedValue>{TypedValue(true), TypedValue("something"),
|
||||
TypedValue(42), TypedValue(0.5), TypedValue()});
|
||||
values_.emplace_back(
|
||||
std::map<std::string, TypedValue>{{"a", true},
|
||||
{"b", "something"},
|
||||
{"c", 42},
|
||||
{"d", 0.5},
|
||||
std::map<std::string, TypedValue>{{"a", TypedValue(true)},
|
||||
{"b", TypedValue("something")},
|
||||
{"c", TypedValue(42)},
|
||||
{"d", TypedValue(0.5)},
|
||||
{"e", TypedValue()}});
|
||||
auto vertex = dba_.InsertVertex();
|
||||
values_.emplace_back(vertex);
|
||||
values_.emplace_back(
|
||||
dba_.InsertEdge(vertex, vertex, dba_.EdgeType("et")));
|
||||
values_.emplace_back(dba_.InsertEdge(vertex, vertex, dba_.EdgeType("et")));
|
||||
values_.emplace_back(query::Path(dba_.InsertVertex()));
|
||||
}
|
||||
};
|
||||
@ -113,22 +113,31 @@ TEST(TypedValue, Equals) {
|
||||
EXPECT_PROP_EQ(TypedValue(std::string("str3")), TypedValue("str3"));
|
||||
|
||||
EXPECT_PROP_NE(TypedValue(std::vector<TypedValue>{1}), TypedValue(1));
|
||||
EXPECT_PROP_NE(TypedValue(std::vector<TypedValue>{1, true, "a"}),
|
||||
TypedValue(std::vector<TypedValue>{1, true, "b"}));
|
||||
EXPECT_PROP_EQ(TypedValue(std::vector<TypedValue>{1, true, "a"}),
|
||||
TypedValue(std::vector<TypedValue>{1, true, "a"}));
|
||||
EXPECT_PROP_NE(TypedValue(std::vector<TypedValue>{
|
||||
TypedValue(1), TypedValue(true), TypedValue("a")}),
|
||||
TypedValue(std::vector<TypedValue>{
|
||||
TypedValue(1), TypedValue(true), TypedValue("b")}));
|
||||
EXPECT_PROP_EQ(TypedValue(std::vector<TypedValue>{
|
||||
TypedValue(1), TypedValue(true), TypedValue("a")}),
|
||||
TypedValue(std::vector<TypedValue>{
|
||||
TypedValue(1), TypedValue(true), TypedValue("a")}));
|
||||
|
||||
EXPECT_PROP_EQ(TypedValue(std::map<std::string, TypedValue>{{"a", 1}}),
|
||||
TypedValue(std::map<std::string, TypedValue>{{"a", 1}}));
|
||||
EXPECT_PROP_NE(TypedValue(std::map<std::string, TypedValue>{{"a", 1}}),
|
||||
TypedValue(1));
|
||||
EXPECT_PROP_NE(TypedValue(std::map<std::string, TypedValue>{{"a", 1}}),
|
||||
TypedValue(std::map<std::string, TypedValue>{{"b", 1}}));
|
||||
EXPECT_PROP_NE(TypedValue(std::map<std::string, TypedValue>{{"a", 1}}),
|
||||
TypedValue(std::map<std::string, TypedValue>{{"a", 2}}));
|
||||
EXPECT_PROP_EQ(
|
||||
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}}),
|
||||
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}}));
|
||||
EXPECT_PROP_NE(
|
||||
TypedValue(std::map<std::string, TypedValue>{{"a", 1}}),
|
||||
TypedValue(std::map<std::string, TypedValue>{{"a", 1}, {"b", 1}}));
|
||||
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}}),
|
||||
TypedValue(1));
|
||||
EXPECT_PROP_NE(
|
||||
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}}),
|
||||
TypedValue(std::map<std::string, TypedValue>{{"b", TypedValue(1)}}));
|
||||
EXPECT_PROP_NE(
|
||||
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}}),
|
||||
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(2)}}));
|
||||
EXPECT_PROP_NE(
|
||||
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}}),
|
||||
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)},
|
||||
{"b", TypedValue(1)}}));
|
||||
}
|
||||
|
||||
TEST(TypedValue, BoolEquals) {
|
||||
@ -148,20 +157,26 @@ TEST(TypedValue, Hash) {
|
||||
EXPECT_EQ(hash(TypedValue(1.5)), hash(TypedValue(1.5)));
|
||||
EXPECT_EQ(hash(TypedValue()), hash(TypedValue()));
|
||||
EXPECT_EQ(hash(TypedValue("bla")), hash(TypedValue("bla")));
|
||||
EXPECT_EQ(hash(TypedValue(std::vector<TypedValue>{1, 2})),
|
||||
hash(TypedValue(std::vector<TypedValue>{1, 2})));
|
||||
EXPECT_EQ(hash(TypedValue(std::map<std::string, TypedValue>{{"a", 1}})),
|
||||
hash(TypedValue(std::map<std::string, TypedValue>{{"a", 1}})));
|
||||
EXPECT_EQ(
|
||||
hash(TypedValue(std::vector<TypedValue>{TypedValue(1), TypedValue(2)})),
|
||||
hash(TypedValue(std::vector<TypedValue>{TypedValue(1), TypedValue(2)})));
|
||||
EXPECT_EQ(
|
||||
hash(TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}})),
|
||||
hash(
|
||||
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}})));
|
||||
|
||||
// these tests are not really true since they expect
|
||||
// hashes to differ, but it's the thought that counts
|
||||
EXPECT_NE(hash(TypedValue(1)), hash(TypedValue(42)));
|
||||
EXPECT_NE(hash(TypedValue(1.5)), hash(TypedValue(2.5)));
|
||||
EXPECT_NE(hash(TypedValue("bla")), hash(TypedValue("johnny")));
|
||||
EXPECT_NE(hash(TypedValue(std::vector<TypedValue>{1, 1})),
|
||||
hash(TypedValue(std::vector<TypedValue>{1, 2})));
|
||||
EXPECT_NE(hash(TypedValue(std::map<std::string, TypedValue>{{"b", 1}})),
|
||||
hash(TypedValue(std::map<std::string, TypedValue>{{"a", 1}})));
|
||||
EXPECT_NE(
|
||||
hash(TypedValue(std::vector<TypedValue>{TypedValue(1), TypedValue(1)})),
|
||||
hash(TypedValue(std::vector<TypedValue>{TypedValue(1), TypedValue(2)})));
|
||||
EXPECT_NE(
|
||||
hash(TypedValue(std::map<std::string, TypedValue>{{"b", TypedValue(1)}})),
|
||||
hash(
|
||||
TypedValue(std::map<std::string, TypedValue>{{"a", TypedValue(1)}})));
|
||||
}
|
||||
|
||||
TEST_F(AllTypesFixture, Less) {
|
||||
@ -223,7 +238,7 @@ TEST(TypedValue, LogicalNot) {
|
||||
TEST(TypedValue, UnaryMinus) {
|
||||
EXPECT_TRUE((-TypedValue()).type() == TypedValue::Type::Null);
|
||||
|
||||
EXPECT_PROP_EQ((-TypedValue(2).Value<int64_t>()), -2);
|
||||
EXPECT_PROP_EQ(TypedValue(-TypedValue(2).Value<int64_t>()), TypedValue(-2));
|
||||
EXPECT_FLOAT_EQ((-TypedValue(2.0).Value<double>()), -2.0);
|
||||
|
||||
EXPECT_THROW(-TypedValue(true), TypedValueException);
|
||||
@ -233,7 +248,7 @@ TEST(TypedValue, UnaryMinus) {
|
||||
TEST(TypedValue, UnaryPlus) {
|
||||
EXPECT_TRUE((+TypedValue()).type() == TypedValue::Type::Null);
|
||||
|
||||
EXPECT_PROP_EQ((+TypedValue(2).Value<int64_t>()), 2);
|
||||
EXPECT_PROP_EQ(TypedValue(+TypedValue(2).Value<int64_t>()), TypedValue(2));
|
||||
EXPECT_FLOAT_EQ((+TypedValue(2.0).Value<double>()), 2.0);
|
||||
|
||||
EXPECT_THROW(+TypedValue(true), TypedValueException);
|
||||
@ -298,26 +313,25 @@ TEST_F(TypedValueArithmeticTest, Sum) {
|
||||
// sum of props of the same type
|
||||
EXPECT_EQ((TypedValue(2) + TypedValue(3)).Value<int64_t>(), 5);
|
||||
EXPECT_FLOAT_EQ((TypedValue(2.5) + TypedValue(1.25)).Value<double>(), 3.75);
|
||||
EXPECT_EQ((TypedValue("one") + TypedValue("two")).ValueString(),
|
||||
"onetwo");
|
||||
EXPECT_EQ((TypedValue("one") + TypedValue("two")).ValueString(), "onetwo");
|
||||
|
||||
// sum of string and numbers
|
||||
EXPECT_EQ((TypedValue("one") + TypedValue(1)).ValueString(), "one1");
|
||||
EXPECT_EQ((TypedValue(1) + TypedValue("one")).ValueString(), "1one");
|
||||
EXPECT_EQ((TypedValue("one") + TypedValue(3.2)).ValueString(),
|
||||
"one3.2");
|
||||
EXPECT_EQ((TypedValue(3.2) + TypedValue("one")).ValueString(),
|
||||
"3.2one");
|
||||
std::vector<TypedValue> in = {1, 2, true, "a"};
|
||||
std::vector<TypedValue> out1 = {2, 1, 2, true, "a"};
|
||||
std::vector<TypedValue> out2 = {1, 2, true, "a", 2};
|
||||
std::vector<TypedValue> out3 = {1, 2, true, "a", 1, 2, true, "a"};
|
||||
EXPECT_PROP_EQ(
|
||||
(TypedValue(2) + TypedValue(in)).ValueList(), out1);
|
||||
EXPECT_PROP_EQ(
|
||||
(TypedValue(in) + TypedValue(2)).ValueList(), out2);
|
||||
EXPECT_PROP_EQ(
|
||||
(TypedValue(in) + TypedValue(in)).ValueList(), out3);
|
||||
EXPECT_EQ((TypedValue("one") + TypedValue(3.2)).ValueString(), "one3.2");
|
||||
EXPECT_EQ((TypedValue(3.2) + TypedValue("one")).ValueString(), "3.2one");
|
||||
std::vector<TypedValue> in{TypedValue(1), TypedValue(2), TypedValue(true),
|
||||
TypedValue("a")};
|
||||
std::vector<TypedValue> out1{TypedValue(2), TypedValue(1), TypedValue(2),
|
||||
TypedValue(true), TypedValue("a")};
|
||||
std::vector<TypedValue> out2{TypedValue(1), TypedValue(2), TypedValue(true),
|
||||
TypedValue("a"), TypedValue(2)};
|
||||
std::vector<TypedValue> out3{
|
||||
TypedValue(1), TypedValue(2), TypedValue(true), TypedValue("a"),
|
||||
TypedValue(1), TypedValue(2), TypedValue(true), TypedValue("a")};
|
||||
EXPECT_PROP_EQ((TypedValue(2) + TypedValue(in)).ValueList(), out1);
|
||||
EXPECT_PROP_EQ((TypedValue(in) + TypedValue(2)).ValueList(), out2);
|
||||
EXPECT_PROP_EQ((TypedValue(in) + TypedValue(in)).ValueList(), out3);
|
||||
}
|
||||
|
||||
TEST_F(TypedValueArithmeticTest, Difference) {
|
||||
|
Loading…
Reference in New Issue
Block a user