Skip to content

'eq', 'ne', 'gt', 'ge', 'lt' and 'le' testers implementation #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions src/filters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,20 +90,6 @@ extern FilterPtr CreateFilter(std::string filterName, CallParams params)
namespace filters
{

bool FilterBase::ParseParams(const std::initializer_list<ArgumentInfo>& argsInfo, const CallParams& params)
{
bool result = true;
m_args = helpers::ParseCallParams(argsInfo, params, result);

return result;
}

InternalValue FilterBase::GetArgumentValue(std::string argName, RenderContext& context, InternalValue defVal)
{
auto argExpr = m_args[argName];
return argExpr ? argExpr->Evaluate(context) : std::move(defVal);
}

Join::Join(FilterParams params)
{
ParseParams({{"d", false, std::string()}, {"attribute"}}, params);
Expand Down
10 changes: 2 additions & 8 deletions src/filters.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define FILTERS_H

#include "expression_evaluator.h"
#include "function_base.h"
#include "jinja2cpp/value.h"
#include "render_context.h"

Expand All @@ -17,15 +18,8 @@ extern FilterPtr CreateFilter(std::string filterName, CallParams params);

namespace filters
{
class FilterBase : public ExpressionFilter::IExpressionFilter
class FilterBase : public FunctionBase, public ExpressionFilter::IExpressionFilter
{
public:
protected:
bool ParseParams(const std::initializer_list<ArgumentInfo>& argsInfo, const CallParams& params);
InternalValue GetArgumentValue(std::string argName, RenderContext& context, InternalValue defVal = InternalValue());

protected:
ParsedArguments m_args;
};

class Attribute : public FilterBase
Expand Down
37 changes: 37 additions & 0 deletions src/function_base.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef FUNCTION_BASE_H
#define FUNCTION_BASE_H

#include "expression_evaluator.h"
#include "internal_value.h"

namespace jinja2
{
class FunctionBase
{
public:
protected:
bool ParseParams(const std::initializer_list<ArgumentInfo>& argsInfo, const CallParams& params);
InternalValue GetArgumentValue(std::string argName, RenderContext& context, InternalValue defVal = InternalValue());

protected:
ParsedArguments m_args;
};


inline bool FunctionBase::ParseParams(const std::initializer_list<ArgumentInfo>& argsInfo, const CallParams& params)
{
bool result = true;
m_args = helpers::ParseCallParams(argsInfo, params, result);

return result;
}

inline InternalValue FunctionBase::GetArgumentValue(std::string argName, RenderContext& context, InternalValue defVal)
{
auto argExpr = m_args[argName];
return argExpr ? argExpr->Evaluate(context) : std::move(defVal);
}

} // jinja2

#endif // FUNCTION_BASE_H
59 changes: 58 additions & 1 deletion src/testers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,43 @@ struct TesterFactory
{
return std::make_shared<F>(std::move(params));
}

template<typename ... Args>
static IsExpression::TesterFactoryFn MakeCreator(Args&& ... args)
{
return [args...](TesterParams params) {return std::make_shared<F>(std::move(params), args...);};
}
};

std::unordered_map<std::string, IsExpression::TesterFactoryFn> s_testers = {
{"defined", &TesterFactory<testers::Defined>::Create},
{"defined", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsDefinedMode)},
{"startsWith", &TesterFactory<testers::StartsWith>::Create},
{"eq", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalEq)},
{"==", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalEq)},
{"equalto", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalEq)},
{"even", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsEvenMode)},
{"ge", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalGe)},
{">=", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalGe)},
{"gt", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalGt)},
{">", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalGt)},
{"greaterthan", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalGt)},
{"in", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsInMode)},
{"iterable", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsIterableMode)},
{"le", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalLe)},
{"<=", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalLe)},
{"lower", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsLowerMode)},
{"lt", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalLt)},
{"<", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalLt)},
{"lessthan", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalLt)},
{"mapping", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsMappingMode)},
{"ne", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalNe)},
{"!=", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalNe)},
{"number", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsNumberMode)},
{"odd", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsOddMode)},
{"sequence", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsSequenceMode)},
{"string", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsStringMode)},
{"undefined", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsUndefinedMode)},
{"upper", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsUpperMode)},
};

TesterPtr CreateTester(std::string testerName, CallParams params)
Expand All @@ -30,10 +62,26 @@ TesterPtr CreateTester(std::string testerName, CallParams params)
namespace testers
{

Comparator::Comparator(TesterParams params, BinaryExpression::Operation op)
: m_op(op)
{
ParseParams({{"b", true}}, params);
}

bool Comparator::Test(const InternalValue& baseVal, RenderContext& context)
{
auto b = GetArgumentValue("b", context);

auto cmpRes = Apply2<visitors::BinaryMathOperation>(baseVal, b, m_op);
return ConvertToBool(cmpRes);
}

#if 0
bool Defined::Test(const InternalValue& baseVal, RenderContext& /*context*/)
{
return boost::get<EmptyValue>(&baseVal) == nullptr;
}
#endif

StartsWith::StartsWith(TesterParams params)
{
Expand All @@ -50,5 +98,14 @@ bool StartsWith::Test(const InternalValue& baseVal, RenderContext& context)
return baseStr.find(str) == 0;
}

ValueTester::ValueTester(TesterParams params, ValueTester::Mode mode)
: m_mode(mode)
{}

bool ValueTester::Test(const InternalValue& baseVal, RenderContext& context)
{
return false;
}

}
}
38 changes: 36 additions & 2 deletions src/testers.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define TESTERS_H

#include "expression_evaluator.h"
#include "function_base.h"
#include "jinja2cpp/value.h"
#include "render_context.h"

Expand All @@ -17,12 +18,19 @@ extern TesterPtr CreateTester(std::string testerName, CallParams params);

namespace testers
{
class Defined : public IsExpression::ITester

class TesterBase : public FunctionBase, public IsExpression::ITester
{
};

class Comparator : public TesterBase
{
public:
Defined(TesterParams) {}
Comparator(TesterParams params, BinaryExpression::Operation op);

bool Test(const InternalValue& baseVal, RenderContext& context) override;
private:
BinaryExpression::Operation m_op;
};

class StartsWith : public IsExpression::ITester
Expand All @@ -36,6 +44,32 @@ class StartsWith : public IsExpression::ITester
ExpressionEvaluatorPtr<> m_stringEval;
};

class ValueTester : public TesterBase
{
public:
enum Mode
{
IsDefinedMode,
IsEvenMode,
IsInMode,
IsIterableMode,
IsLowerMode,
IsMappingMode,
IsNumberMode,
IsOddMode,
IsSequenceMode,
IsStringMode,
IsUndefinedMode,
IsUpperMode
};

ValueTester(TesterParams params, Mode mode);

bool Test(const InternalValue& baseVal, RenderContext& context) override;
private:
Mode m_mode;
};

} // testers
} // jinja2

Expand Down
2 changes: 1 addition & 1 deletion test/expressions_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ Hello; world!!!
TEST(ExpressionsTest, IfExpression)
{
std::string source = R"(
{{ intValue if doubleValue is defined }}
{{ intValue if intValue is eq(3) }}
{{ stringValue if intValue < 3 else doubleValue }}
)";

Expand Down
1 change: 1 addition & 0 deletions test/test_tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ inline jinja2::ValuesMap PrepareTestData()
{"intList", jinja2::ValuesList{9, 0, 8, 1, 7, 2, 6, 3, 5, 4}},
{"doubleValue", 12.123f},
{"doubleList", jinja2::ValuesList{9.5, 0.5, 8.5, 1.5, 7.5, 2.5, 6.4, 3.8, 5.2, -4.7}},
{"intAsDoubleList", jinja2::ValuesList{9.0, 0.0, 8.0, 1.0, 7.0, 2.0, 6.0, 3.0, 5.0, 4.0}},
{"stringValue", "rain"},
{"wstringValue", std::wstring(L" hello world ")},
{"stringList", jinja2::ValuesList{"string9", "string0", "string8", "string1", "string7", "string2", "string6", "string3", "string5", "string4"}},
Expand Down
136 changes: 136 additions & 0 deletions test/testers_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#include <iostream>
#include <string>

#include "test_tools.h"
#include "jinja2cpp/template.h"

using namespace jinja2;

struct TestersGenericTestTag;
using TestersGenericTest = InputOutputPairTest<TestersGenericTestTag>;


TEST_P(TestersGenericTest, Test)
{
auto& testParam = GetParam();
std::string source = "{{ 'true' if " + testParam.tpl + " else 'false'}}";

Template tpl;
ASSERT_TRUE(tpl.Load(source));

std::string result = tpl.RenderAsString(PrepareTestData());
std::cout << result << std::endl;
std::string expectedResult = testParam.result;
EXPECT_EQ(expectedResult, result);
}

INSTANTIATE_TEST_CASE_P(EqTest, TestersGenericTest, ::testing::Values(
InputOutputPair{"0 is eq(0)", "true"},
InputOutputPair{"0 is eq(1)", "false"},
InputOutputPair{"0.5 is eq(0.5)", "true"},
InputOutputPair{"0.5 is eq(1.5)", "false"},
InputOutputPair{"'0.5' is eq('0.5')", "true"},
InputOutputPair{"'0.5' is eq('1.5')", "false"},
InputOutputPair{"'Hello World' is eq('hello world')", "false"},
InputOutputPair{"0 is equalto(1)", "false"},
InputOutputPair{"intList[0] is eq(intAsDoubleList[0])", "true"},
InputOutputPair{"intAsDoubleList[0] is eq(intList[0])", "true"}
));


INSTANTIATE_TEST_CASE_P(NeTest, TestersGenericTest, ::testing::Values(
InputOutputPair{"0 is ne(0)", "false"},
InputOutputPair{"0 is ne(1)", "true"},
InputOutputPair{"0.5 is ne(0.5)", "false"},
InputOutputPair{"0.5 is ne(1.5)", "true"},
InputOutputPair{"'0.5' is ne('0.5')", "false"},
InputOutputPair{"'0.5' is ne('1.5')", "true"},
InputOutputPair{"'Hello World' is ne('hello world')", "true"},
InputOutputPair{"intList[0] is ne(intAsDoubleList[0])", "false"},
InputOutputPair{"intAsDoubleList[0] is ne(intList[0])", "false"}
));


INSTANTIATE_TEST_CASE_P(GeTest, TestersGenericTest, ::testing::Values(
InputOutputPair{"0 is ge(0)", "true"},
InputOutputPair{"0 is ge(1)", "false"},
InputOutputPair{"1 is ge(0)", "true"},
InputOutputPair{"0.5 is ge(0.5)", "true"},
InputOutputPair{"0.5 is ge(1.5)", "false"},
InputOutputPair{"1.5 is ge(0.5)", "true"},
InputOutputPair{"'0.5' is ge('0.5')", "true"},
InputOutputPair{"'0.5' is ge('1.5')", "false"},
InputOutputPair{"'1.5' is ge('0.5')", "true"},
InputOutputPair{"'Hello World' is ge('hello world')", "false"},
InputOutputPair{"'hello world' is ge('Hello World')", "true"},
InputOutputPair{"intList[0] is ge(intAsDoubleList[0])", "true"},
InputOutputPair{"intList[0] is ge(intAsDoubleList[1])", "true"},
InputOutputPair{"intList[1] is ge(intAsDoubleList[0])", "false"},
InputOutputPair{"intAsDoubleList[0] is ge(intList[0])", "true"},
InputOutputPair{"intAsDoubleList[0] is ge(intList[1])", "true"},
InputOutputPair{"intAsDoubleList[1] is ge(intList[0])", "false"}
));


INSTANTIATE_TEST_CASE_P(GtTest, TestersGenericTest, ::testing::Values(
InputOutputPair{"0 is gt(0)", "false"},
InputOutputPair{"0 is greaterthan(0)", "false"},
InputOutputPair{"0 is gt(1)", "false"},
InputOutputPair{"1 is greaterthan(0)", "true"},
InputOutputPair{"0.5 is gt(0.5)", "false"},
InputOutputPair{"0.5 is gt(1.5)", "false"},
InputOutputPair{"1.5 is gt(0.5)", "true"},
InputOutputPair{"'0.5' is gt('0.5')", "false"},
InputOutputPair{"'0.5' is gt('1.5')", "false"},
InputOutputPair{"'1.5' is gt('0.5')", "true"},
InputOutputPair{"'Hello World' is gt('hello world')", "false"},
InputOutputPair{"'hello world' is gt('Hello World')", "true"},
InputOutputPair{"intList[0] is gt(intAsDoubleList[0])", "false"},
InputOutputPair{"intList[0] is gt(intAsDoubleList[1])", "true"},
InputOutputPair{"intList[1] is gt(intAsDoubleList[0])", "false"},
InputOutputPair{"intAsDoubleList[0] is gt(intList[0])", "false"},
InputOutputPair{"intAsDoubleList[0] is gt(intList[1])", "true"},
InputOutputPair{"intAsDoubleList[1] is gt(intList[0])", "false"}
));

INSTANTIATE_TEST_CASE_P(LeTest, TestersGenericTest, ::testing::Values(
InputOutputPair{"0 is le(0)", "true"},
InputOutputPair{"0 is le(1)", "true"},
InputOutputPair{"1 is le(0)", "false"},
InputOutputPair{"0.5 is le(0.5)", "true"},
InputOutputPair{"0.5 is le(1.5)", "true"},
InputOutputPair{"1.5 is le(0.5)", "false"},
InputOutputPair{"'0.5' is le('0.5')", "true"},
InputOutputPair{"'0.5' is le('1.5')", "true"},
InputOutputPair{"'1.5' is le('0.5')", "false"},
InputOutputPair{"'Hello World' is le('hello world')", "true"},
InputOutputPair{"'hello world' is le('Hello World')", "false"},
InputOutputPair{"intList[0] is le(intAsDoubleList[0])", "true"},
InputOutputPair{"intList[0] is le(intAsDoubleList[1])", "false"},
InputOutputPair{"intList[1] is le(intAsDoubleList[0])", "true"},
InputOutputPair{"intAsDoubleList[0] is le(intList[0])", "true"},
InputOutputPair{"intAsDoubleList[0] is le(intList[1])", "false"},
InputOutputPair{"intAsDoubleList[1] is le(intList[0])", "true"}
));


INSTANTIATE_TEST_CASE_P(LtTest, TestersGenericTest, ::testing::Values(
InputOutputPair{"0 is lt(0)", "false"},
InputOutputPair{"0 is lessthan(0)", "false"},
InputOutputPair{"0 is lessthan(1)", "true"},
InputOutputPair{"1 is lt(0)", "false"},
InputOutputPair{"0.5 is lt(0.5)", "false"},
InputOutputPair{"0.5 is lt(1.5)", "true"},
InputOutputPair{"1.5 is lt(0.5)", "false"},
InputOutputPair{"'0.5' is lt('0.5')", "false"},
InputOutputPair{"'0.5' is lt('1.5')", "true"},
InputOutputPair{"'1.5' is lt('0.5')", "false"},
InputOutputPair{"'Hello World' is lt('hello world')", "true"},
InputOutputPair{"'hello world' is lt('Hello World')", "false"},
InputOutputPair{"intList[0] is lt(intAsDoubleList[0])", "false"},
InputOutputPair{"intList[0] is lt(intAsDoubleList[1])", "false"},
InputOutputPair{"intList[1] is lt(intAsDoubleList[0])", "true"},
InputOutputPair{"intAsDoubleList[0] is lt(intList[0])", "false"},
InputOutputPair{"intAsDoubleList[0] is lt(intList[1])", "false"},
InputOutputPair{"intAsDoubleList[1] is lt(intList[0])", "true"}
));