shushus

Спринт 16. Разработка runtime-модуля.

Jun 22nd, 2023
238
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 38.52 KB | None | 0 0
  1. -----------------------------------------------------------------------
  2. runtime.h
  3. -----------------------------------------------------------------------
  4. #pragma once
  5.  
  6. #include <memory>
  7. #include <sstream>
  8. #include <string>
  9. #include <unordered_map>
  10. #include <vector>
  11. #include <cassert>
  12.  
  13. namespace runtime {
  14.  
  15. class Context {
  16. public:
  17.     virtual std::ostream& GetOutputStream() = 0;
  18.  
  19. protected:
  20.     ~Context() = default;
  21. };
  22.  
  23. class Object {
  24. public:
  25.     virtual ~Object() = default;
  26.     virtual void Print(std::ostream& os, Context& context) = 0;
  27. };
  28.  
  29. class ObjectHolder {
  30. public:
  31.     ObjectHolder() = default;
  32.  
  33.     template <typename T>
  34.     [[nodiscard]] static ObjectHolder Own(T&& object) {
  35.         return ObjectHolder(std::make_shared<T>(std::forward<T>(object)));
  36.     }
  37.  
  38.     [[nodiscard]] static ObjectHolder Share(Object& object);
  39.     [[nodiscard]] static ObjectHolder None();
  40.  
  41.     Object& operator*() const;
  42.     Object* operator->() const;
  43.     [[nodiscard]] Object* Get() const;
  44.  
  45.     template <typename T>
  46.     [[nodiscard]] T* TryAs() const {return dynamic_cast<T*>(this->Get());}
  47.  
  48.     explicit operator bool() const;
  49.  
  50. private:
  51.    
  52.     explicit ObjectHolder(std::shared_ptr<Object> data);  
  53.     void AssertIsValid() const;
  54.     std::shared_ptr<Object> data_;
  55. };
  56.  
  57. template <typename T>
  58. class ValueObject : public Object {
  59. public:
  60.    
  61.     ValueObject(T v) : value_(v) {}
  62.     void Print(std::ostream& os, [[maybe_unused]] Context& context) override {os << value_;}
  63.     [[nodiscard]] const T& GetValue() const {return value_;}
  64.  
  65. private:
  66.     T value_;
  67. };
  68.  
  69. using Closure = std::unordered_map<std::string, ObjectHolder>;
  70. bool IsTrue(const ObjectHolder& object);
  71.    
  72. class Executable {
  73. public:
  74.     virtual ~Executable() = default;
  75.     virtual ObjectHolder Execute(Closure& closure, Context& context) = 0;
  76. };
  77.  
  78. using String = ValueObject<std::string>;
  79. using Number = ValueObject<int>;
  80.  
  81. class Bool : public ValueObject<bool> {
  82. public:
  83.    
  84.     using ValueObject<bool>::ValueObject;
  85.     void Print(std::ostream& os, Context& context) override;
  86. };
  87.  
  88. struct Method {
  89.     std::string name;
  90.     std::vector<std::string> formal_params;
  91.     std::unique_ptr<Executable> body;
  92. };
  93.  
  94. class Class : public Object {
  95. public:
  96.  
  97.     explicit Class(std::string name, std::vector<Method> methods, const Class* parent);
  98.     [[nodiscard]] const Method* GetMethod(const std::string& name) const;
  99.     [[nodiscard]] const std::string& GetName() const;
  100.     void Print(std::ostream& os, Context& context) override;
  101.    
  102. private:
  103.  
  104.     std::unordered_map<std::string_view, const Method*> methods_with_name_;
  105.     std::string name_;
  106.     std::vector<Method> methods_;
  107.    
  108.     const Class* parent_ = nullptr;
  109. };
  110.  
  111. class ClassInstance : public Object {
  112. public:
  113.     explicit ClassInstance(const Class& cls);
  114.  
  115.     void Print(std::ostream& os, Context& context) override;
  116.  
  117.     ObjectHolder Call(const std::string& method, const std::vector<ObjectHolder>& actual_args, Context& context);
  118.     [[nodiscard]] bool HasMethod(const std::string& method, size_t argument_count) const;
  119.     [[nodiscard]] Closure& Fields();
  120.     [[nodiscard]] const Closure& Fields() const;
  121.    
  122. private:
  123.     const Class& class_;
  124.     Closure fields_;
  125. };
  126.  
  127. bool Equal(const ObjectHolder& lhs, const ObjectHolder& rhs, Context& context);
  128. bool Less(const ObjectHolder& lhs, const ObjectHolder& rhs, Context& context);
  129. bool NotEqual(const ObjectHolder& lhs, const ObjectHolder& rhs, Context& context);
  130. bool Greater(const ObjectHolder& lhs, const ObjectHolder& rhs, Context& context);
  131. bool LessOrEqual(const ObjectHolder& lhs, const ObjectHolder& rhs, Context& context);
  132. bool GreaterOrEqual(const ObjectHolder& lhs, const ObjectHolder& rhs, Context& context);
  133.  
  134. struct DummyContext : Context {
  135.    
  136.     std::ostream& GetOutputStream() override {return output;}
  137.     std::ostringstream output;
  138. };
  139.  
  140. class SimpleContext : public runtime::Context {
  141. public:
  142.    
  143.     explicit SimpleContext(std::ostream& output) : output_(output) {}
  144.     std::ostream& GetOutputStream() override {return output_;}
  145.  
  146. private:
  147.     std::ostream& output_;
  148. };
  149.  
  150. }//end namespace runtime
  151. -----------------------------------------------------------------------
  152. runtime.cpp
  153. -----------------------------------------------------------------------
  154. #include "runtime.h"
  155.  
  156. #include <cassert>
  157. #include <optional>
  158. #include <sstream>
  159.  
  160. using namespace std;
  161.  
  162. namespace runtime {
  163.  
  164. ObjectHolder::ObjectHolder(std::shared_ptr<Object> data) : data_(std::move(data)) {}
  165. void ObjectHolder::AssertIsValid() const {assert(data_ != nullptr);}
  166.  
  167. ObjectHolder ObjectHolder::Share(Object& object) {return ObjectHolder(std::shared_ptr<Object>(&object, [](auto*) {}));}
  168. ObjectHolder ObjectHolder::None() {return ObjectHolder();}
  169.  
  170. Object& ObjectHolder::operator*() const {
  171.     AssertIsValid();
  172.     return *Get();
  173. }
  174.  
  175. Object* ObjectHolder::operator->() const {
  176.     AssertIsValid();
  177.     return Get();
  178. }
  179.  
  180. Object* ObjectHolder::Get() const {return data_.get();}
  181. ObjectHolder::operator bool() const {return Get() != nullptr;}
  182.  
  183. bool IsTrue(const ObjectHolder& object) {
  184.    
  185.     if (!object) {return false;}
  186.    
  187.     auto object_boolean = object.TryAs<Bool>();
  188.     if (object_boolean) {return object_boolean->GetValue();}
  189.    
  190.     auto object_string = object.TryAs<String>();
  191.     if (object_string && !object_string->GetValue().empty()) {return true;}
  192.    
  193.     auto object_number = object.TryAs<Number>();
  194.     if (object_number && object_number->GetValue() != 0) {return true;}
  195.    
  196.     auto object_val_boolean = object.TryAs<ValueObject<bool>>();
  197.     if (object_val_boolean) {return object_val_boolean->GetValue();}
  198.    
  199.     return false;
  200. }
  201.  
  202. void ClassInstance::Print(std::ostream& os, Context& context) {
  203.    
  204.     if (this->HasMethod("__str__", 0)) {
  205.         this->Call("__str__", {}, context)->Print(os, context);
  206.        
  207.     } else {
  208.         os << this;
  209.     }
  210. }
  211.  
  212. bool ClassInstance::HasMethod(const std::string& method, size_t argument_count) const {
  213.     return (class_.GetMethod(method) && class_.GetMethod(method)->formal_params.size() == argument_count);
  214. }
  215.  
  216. Closure& ClassInstance::Fields() {return fields_;}
  217. const Closure& ClassInstance::Fields() const {return fields_;}
  218. ClassInstance::ClassInstance(const Class& cls) : class_(cls) {}
  219.  
  220. ObjectHolder ClassInstance::Call(const std::string& method, const std::vector<ObjectHolder>& actual_args, Context& context) {
  221.    
  222.     if (!this->HasMethod(method, actual_args.size())) {
  223.         throw std::runtime_error("not implemented"s);
  224.     }
  225.    
  226.     Closure closure = {{"self", ObjectHolder::Share(*this)}};
  227.     auto method_ptr = class_.GetMethod(method);
  228.    
  229.     for (size_t i = 0; i < method_ptr->formal_params.size(); ++i) {
  230.         auto arg = method_ptr->formal_params[i];
  231.         closure[arg] = actual_args[i];
  232.     }
  233.    
  234.     return method_ptr->body->Execute(closure, context);
  235. }
  236.  
  237. Class::Class(std::string name, std::vector<Method> methods, const Class* parent) : name_(std::move(name))
  238.                                                                                  , methods_(std::move(methods))
  239.                                                                                  , parent_(std::move(parent)) {
  240.     if (parent_) {
  241.        
  242.         for (const auto& method : parent_->methods_) {
  243.             methods_with_name_[method.name] = &method;
  244.         }
  245.     }
  246.    
  247.     for (const auto& method : methods_) {
  248.         methods_with_name_[method.name] = &method;
  249.     }
  250. }
  251.  
  252. const Method* Class::GetMethod(const std::string& name) const {
  253.    
  254.     if (methods_with_name_.find(name) != methods_with_name_.end()) {
  255.         return methods_with_name_.at(name);
  256.        
  257.     } else {
  258.         return nullptr;
  259.     }
  260. }
  261.  
  262. const std::string& Class::GetName() const {return name_;}
  263. void Class::Print(ostream& os, [[maybe_unused]] Context& context) {os <<"Class "sv << GetName();}
  264. void Bool::Print(std::ostream& os, [[maybe_unused]] Context& context) {os << (GetValue() ? "True"sv : "False"sv);}
  265.  
  266. bool Equal(const ObjectHolder& lhs, const ObjectHolder& rhs, Context& context) {
  267.    
  268.     if (!lhs && !rhs) {
  269.         return true;
  270.        
  271.     } else {
  272.        
  273.         if (!lhs) {
  274.             throw std::runtime_error("invalid args. cannot compare. == or !="s);
  275.            
  276.         } else {
  277.            
  278.             auto lhs_string = lhs.TryAs<String>();
  279.             auto rhs_string = rhs.TryAs<String>();        
  280.             if (lhs_string && rhs_string) {return lhs_string->GetValue() == rhs_string->GetValue();}
  281.  
  282.             auto lhs_number = lhs.TryAs<Number>();
  283.             auto rhs_number = rhs.TryAs<Number>();
  284.             if (lhs_number && rhs_number) {return lhs_number->GetValue() == rhs_number->GetValue();}
  285.  
  286.             auto lhs_boolean = lhs.TryAs<Bool>();
  287.             auto rhs_boolean = rhs.TryAs<Bool>();
  288.             if (lhs_boolean && rhs_boolean) {return lhs_boolean->GetValue() == rhs_boolean->GetValue();}
  289.  
  290.             auto lhs_class = lhs.TryAs<ClassInstance>();
  291.             if (lhs_class && lhs_class->HasMethod("__eq__", 1)) {
  292.  
  293.                 auto result = lhs_class->Call("__eq__", {rhs}, context);
  294.                 return result.TryAs<Bool>()->GetValue();
  295.             }
  296.  
  297.             throw std::runtime_error("invalid args. cannot compare. == or !="s);
  298.         }
  299.     }
  300. }
  301.  
  302. bool Less(const ObjectHolder& lhs, const ObjectHolder& rhs, Context& context) {
  303.    
  304.     if (!lhs) {
  305.         throw std::runtime_error("invalid args. cannot compare. < or >"s);
  306.        
  307.     } else {
  308.        
  309.         auto lhs_string = lhs.TryAs<String>();
  310.         auto rhs_string = rhs.TryAs<String>();
  311.         if (lhs_string && rhs_string) {return lhs_string->GetValue() < rhs_string->GetValue();}
  312.        
  313.         auto lhs_number = lhs.TryAs<Number>();
  314.         auto rhs_number = rhs.TryAs<Number>();
  315.         if (lhs_number && rhs_number) {return lhs_number->GetValue() < rhs_number->GetValue();}
  316.        
  317.         auto lhs_boolean = lhs.TryAs<Bool>();
  318.         auto rhs_boolean = rhs.TryAs<Bool>();
  319.         if (lhs_boolean && rhs_boolean) {return lhs_boolean->GetValue() < rhs_boolean->GetValue();}
  320.        
  321.         auto lhs_class = lhs.TryAs<ClassInstance>();
  322.         if (lhs_class && lhs_class->HasMethod("__lt__", 1)) {
  323.            
  324.             auto result = lhs_class->Call("__lt__", { rhs }, context);
  325.             return result.TryAs<Bool>()->GetValue();
  326.         }
  327.        
  328.         throw std::runtime_error("invalid args. cannot compare. < or >"s);
  329.     }
  330. }
  331.  
  332. bool NotEqual(const ObjectHolder& lhs, const ObjectHolder& rhs, Context& context) {return !Equal(lhs, rhs, context);}
  333. bool Greater(const ObjectHolder& lhs, const ObjectHolder& rhs, Context& context) {return !Less(lhs, rhs, context) && !Equal(lhs, rhs, context);}
  334. bool LessOrEqual(const ObjectHolder& lhs, const ObjectHolder& rhs, Context& context) {return Less(lhs, rhs, context) || Equal(lhs, rhs, context);}
  335. bool GreaterOrEqual(const ObjectHolder& lhs, const ObjectHolder& rhs, Context& context) {return !Less(lhs, rhs, context);}
  336.  
  337. }//end namespace runtime
  338. -----------------------------------------------------------------------
  339. main.cpp
  340. -----------------------------------------------------------------------
  341. #include "runtime.h"
  342. #include "test_runner_p.h"
  343.  
  344. using namespace std;
  345.  
  346. namespace runtime {
  347.    
  348. void RunObjectHolderTests(TestRunner& tr);
  349. void RunObjectsTests(TestRunner& tr);
  350.    
  351. }//end namespace runtime
  352.  
  353. namespace {
  354.  
  355. void TestAll() {
  356.     TestRunner tr;
  357.     runtime::RunObjectHolderTests(tr);
  358.     runtime::RunObjectsTests(tr);
  359. }
  360.  
  361. }//end namespace
  362.  
  363. int main() {
  364.     TestAll();
  365.     return 0;
  366. }
  367. -----------------------------------------------------------------------
  368. runtime_test.cpp
  369. -----------------------------------------------------------------------
  370. #include "runtime.h"
  371. #include "test_runner_p.h"
  372.  
  373. #include <functional>
  374.  
  375. using namespace std;
  376.  
  377. namespace runtime {
  378.  
  379. namespace {
  380. class Logger : public Object {
  381. public:
  382.     static int instance_count;
  383.  
  384.     explicit Logger(int value_ = 0) : id_(value_) {++instance_count;}
  385.  
  386.     Logger(const Logger& rhs) : id_(rhs.id_) {++instance_count;}
  387.     Logger(Logger&& rhs) noexcept : id_(rhs.id_) {++instance_count;}
  388.     Logger& operator=(const Logger&) = default;
  389.     Logger& operator=(Logger&&) = default;
  390.  
  391.     [[nodiscard]] int GetId() const {return id_;}
  392.    
  393.     ~Logger() {--instance_count;}
  394.     void Print(ostream& os, [[maybe_unused]] Context& context) override {os << id_;}
  395.  
  396. private:
  397.     int id_;
  398. };
  399.  
  400. int Logger::instance_count = 0;
  401.  
  402. void TestNumber() {
  403.     Number num(127);
  404.  
  405.     DummyContext context;
  406.  
  407.     num.Print(context.output, context);
  408.     ASSERT_EQUAL(context.output.str(), "127"s);
  409.     ASSERT_EQUAL(num.GetValue(), 127);
  410. }
  411.  
  412. void TestString() {
  413.     String word("hello!"s);
  414.  
  415.     DummyContext context;
  416.     word.Print(context.output, context);
  417.     ASSERT_EQUAL(context.output.str(), "hello!"s);
  418.     ASSERT_EQUAL(word.GetValue(), "hello!"s);
  419. }
  420.  
  421. void TestBool() {
  422.     Bool t(true);
  423.     ASSERT_EQUAL(t.GetValue(), true);
  424.  
  425.     DummyContext context;
  426.     ostringstream out;
  427.     t.Print(out, context);
  428.     ASSERT_EQUAL(out.str(), "True"s);
  429.     out.str({});
  430.  
  431.     Bool f(false);
  432.     ASSERT_EQUAL(f.GetValue(), false);
  433.  
  434.     f.Print(out, context);
  435.     ASSERT_EQUAL(out.str(), "False"s);
  436.  
  437.     ASSERT(context.output.str().empty());
  438. }
  439.  
  440. struct TestMethodBody : Executable {
  441.     using Fn = std::function<ObjectHolder(Closure& closure, Context& context)>;
  442.     Fn body;
  443.  
  444.     explicit TestMethodBody(Fn body) : body(std::move(body)) {}
  445.  
  446.     ObjectHolder Execute(Closure& closure, Context& context) override {
  447.        
  448.         if (body) {
  449.             return body(closure, context);
  450.         } else {
  451.             return {};
  452.         }    
  453.     }
  454. };
  455.  
  456. void TestMethodInvocation() {
  457.     DummyContext context;
  458.     Closure base_closure;
  459.     auto base_method_1 = [&base_closure, &context](Closure& closure, Context& ctx) {
  460.         ASSERT_EQUAL(&context, &ctx);
  461.         base_closure = closure;
  462.         return ObjectHolder::Own(Number{123});
  463.     };
  464.     auto base_method_2 = [&base_closure, &context](Closure& closure, Context& ctx) {
  465.         ASSERT_EQUAL(&context, &ctx);
  466.         base_closure = closure;
  467.         return ObjectHolder::Own(Number{456});
  468.     };
  469.     vector<Method> base_methods;
  470.     base_methods.push_back(
  471.         {"test"s, {"arg1"s, "arg2"s}, make_unique<TestMethodBody>(base_method_1)});
  472.     base_methods.push_back({"test_2"s, {"arg1"s}, make_unique<TestMethodBody>(base_method_2)});
  473.     Class base_class{"Base"s, std::move(base_methods), nullptr};
  474.     ClassInstance base_inst{base_class};
  475.     base_inst.Fields()["base_field"s] = ObjectHolder::Own(String{"hello"s});
  476.     ASSERT(base_inst.HasMethod("test"s, 2U));
  477.     auto res = base_inst.Call(
  478.         "test"s, {ObjectHolder::Own(Number{1}), ObjectHolder::Own(String{"abc"s})}, context);
  479.     ASSERT(Equal(res, ObjectHolder::Own(Number{123}), context));
  480.     ASSERT_EQUAL(base_closure.size(), 3U);
  481.     ASSERT_EQUAL(base_closure.count("self"s), 1U);
  482.     ASSERT_EQUAL(base_closure.at("self"s).Get(), &base_inst);
  483.     ASSERT_EQUAL(base_closure.count("self"s), 1U);
  484.     ASSERT_EQUAL(base_closure.count("arg1"s), 1U);
  485.     ASSERT(Equal(base_closure.at("arg1"s), ObjectHolder::Own(Number{1}), context));
  486.     ASSERT_EQUAL(base_closure.count("arg2"s), 1U);
  487.     ASSERT(Equal(base_closure.at("arg2"s), ObjectHolder::Own(String{"abc"s}), context));
  488.     ASSERT_EQUAL(base_closure.count("base_field"s), 0U);
  489.  
  490.     Closure child_closure;
  491.     auto child_method_1 = [&child_closure, &context](Closure& closure, Context& ctx) {
  492.         ASSERT_EQUAL(&context, &ctx);
  493.         child_closure = closure;
  494.         return ObjectHolder::Own(String("child"s));
  495.     };
  496.     vector<Method> child_methods;
  497.     child_methods.push_back(
  498.         {"test"s, {"arg1_child"s, "arg2_child"s}, make_unique<TestMethodBody>(child_method_1)});
  499.     Class child_class{"Child"s, std::move(child_methods), &base_class};
  500.     ClassInstance child_inst{child_class};
  501.     ASSERT(child_inst.HasMethod("test"s, 2U));
  502.     base_closure.clear();
  503.     res = child_inst.Call(
  504.         "test"s, {ObjectHolder::Own(String{"value1"s}), ObjectHolder::Own(String{"value2"s})},
  505.         context);
  506.     ASSERT(Equal(res, ObjectHolder::Own(String{"child"s}), context));
  507.     ASSERT(base_closure.empty());
  508.     ASSERT_EQUAL(child_closure.size(), 3U);
  509.     ASSERT_EQUAL(child_closure.count("self"s), 1U);
  510.     ASSERT_EQUAL(child_closure.at("self"s).Get(), &child_inst);
  511.     ASSERT_EQUAL(child_closure.count("arg1_child"s), 1U);
  512.     ASSERT(Equal(child_closure.at("arg1_child"s), (ObjectHolder::Own(String{"value1"s})), context));
  513.     ASSERT_EQUAL(child_closure.count("arg2_child"s), 1U);
  514.     ASSERT(Equal(child_closure.at("arg2_child"s), (ObjectHolder::Own(String{"value2"s})), context));
  515.  
  516.     ASSERT(child_inst.HasMethod("test_2"s, 1U));
  517.     child_closure.clear();
  518.     res = child_inst.Call("test_2"s, {ObjectHolder::Own(String{":)"s})}, context);
  519.     ASSERT(Equal(res, ObjectHolder::Own(Number{456}), context));
  520.     ASSERT_EQUAL(base_closure.size(), 2U);
  521.     ASSERT_EQUAL(base_closure.count("self"s), 1U);
  522.     ASSERT_EQUAL(base_closure.at("self"s).Get(), &child_inst);
  523.     ASSERT_EQUAL(base_closure.count("arg1"s), 1U);
  524.     ASSERT(Equal(base_closure.at("arg1"s), (ObjectHolder::Own(String{":)"s})), context));
  525.  
  526.     ASSERT(!child_inst.HasMethod("test"s, 1U));
  527.     ASSERT_THROWS(child_inst.Call("test"s, {ObjectHolder::None()}, context), runtime_error);
  528. }
  529.  
  530. void TestNonowning() {
  531.     ASSERT_EQUAL(Logger::instance_count, 0);
  532.     Logger logger(784);
  533.     {
  534.         auto oh = ObjectHolder::Share(logger);
  535.         ASSERT(oh);
  536.     }
  537.     ASSERT_EQUAL(Logger::instance_count, 1);
  538.  
  539.     auto oh = ObjectHolder::Share(logger);
  540.     ASSERT(oh);
  541.     ASSERT(oh.Get() == &logger);
  542.  
  543.     DummyContext context;
  544.     oh->Print(context.output, context);
  545.  
  546.     ASSERT_EQUAL(context.output.str(), "784"sv);
  547. }
  548.  
  549. void TestOwning() {
  550.     ASSERT_EQUAL(Logger::instance_count, 0);
  551.     {
  552.         auto oh = ObjectHolder::Own(Logger());
  553.         ASSERT(oh);
  554.         ASSERT_EQUAL(Logger::instance_count, 1);
  555.     }
  556.     ASSERT_EQUAL(Logger::instance_count, 0);
  557.  
  558.     auto oh = ObjectHolder::Own(Logger(312));
  559.     ASSERT(oh);
  560.     ASSERT_EQUAL(Logger::instance_count, 1);
  561.  
  562.     DummyContext context;
  563.     oh->Print(context.output, context);
  564.  
  565.     ASSERT_EQUAL(context.output.str(), "312"sv);
  566. }
  567.  
  568. void TestMove() {
  569.     {
  570.         ASSERT_EQUAL(Logger::instance_count, 0);
  571.         Logger logger;
  572.  
  573.         auto one = ObjectHolder::Share(logger);
  574.         ObjectHolder two = std::move(one);
  575.  
  576.         ASSERT_EQUAL(Logger::instance_count, 1);
  577.         ASSERT(two.Get() == &logger);
  578.     }
  579.     {
  580.         ASSERT_EQUAL(Logger::instance_count, 0);
  581.         auto one = ObjectHolder::Own(Logger());
  582.         ASSERT_EQUAL(Logger::instance_count, 1);
  583.         Object* stored = one.Get();
  584.         ObjectHolder two = std::move(one);
  585.         ASSERT_EQUAL(Logger::instance_count, 1);
  586.  
  587.         ASSERT(two.Get() == stored);
  588.         ASSERT(!one);
  589.     }
  590. }
  591.  
  592. void TestNullptr() {
  593.     ObjectHolder oh;
  594.     ASSERT(!oh);
  595.     ASSERT(!oh.Get());
  596. }
  597.  
  598. void TestIsTrue() {
  599.     {
  600.         ASSERT(!IsTrue(ObjectHolder::Own(Bool{false})));
  601.         ASSERT(IsTrue(ObjectHolder::Own(Bool{true})));
  602.     }
  603.  
  604.     ASSERT(!IsTrue(ObjectHolder::None()));
  605.  
  606.     {
  607.         ASSERT(!IsTrue(ObjectHolder::Own(Number{0})));
  608.         ASSERT(IsTrue(ObjectHolder::Own(Number{1})));
  609.         ASSERT(IsTrue(ObjectHolder::Own(Number{-1})));
  610.         ASSERT(IsTrue(ObjectHolder::Own(Number{42})));
  611.     }
  612.  
  613.     {
  614.         ASSERT(!IsTrue(ObjectHolder::Own(String{""s})));
  615.         ASSERT(IsTrue(ObjectHolder::Own(String{"0"s})));
  616.         ASSERT(IsTrue(ObjectHolder::Own(String{"1"s})));
  617.         ASSERT(IsTrue(ObjectHolder::Own(String{"abc"s})));
  618.         ASSERT(IsTrue(ObjectHolder::Own(String{"True"s})));
  619.         ASSERT(IsTrue(ObjectHolder::Own(String{"False"s})));
  620.     }
  621.  
  622.     {
  623.         Class cls{"Test"s, {}, nullptr};
  624.         ASSERT(!IsTrue(ObjectHolder::Share(cls)));
  625.         ASSERT(!IsTrue(ObjectHolder::Own(ClassInstance{cls})));
  626.     }
  627. }
  628.  
  629. void TestComparison() {
  630.     auto test_equal = [](const ObjectHolder& lhs, const ObjectHolder& rhs, bool equality_result) {
  631.         DummyContext ctx;
  632.         ASSERT(Equal(lhs, rhs, ctx) == equality_result);
  633.         ASSERT(NotEqual(lhs, rhs, ctx) == !equality_result);
  634.     };
  635.  
  636.     auto test_less = [](const ObjectHolder& lhs, const ObjectHolder& rhs, bool less_result) {
  637.         DummyContext ctx;
  638.         ASSERT(Less(lhs, rhs, ctx) == less_result);
  639.         ASSERT(GreaterOrEqual(lhs, rhs, ctx) == !less_result);
  640.     };
  641.  
  642.     auto test_greater = [](const ObjectHolder& lhs, const ObjectHolder& rhs, bool greater_result) {
  643.         DummyContext ctx;
  644.         ASSERT(Greater(lhs, rhs, ctx) == greater_result);
  645.         ASSERT(LessOrEqual(lhs, rhs, ctx) == !greater_result);
  646.     };
  647.  
  648.     auto test_eq_uncomparable = [](const ObjectHolder& lhs, const ObjectHolder& rhs) {
  649.         DummyContext ctx;
  650.         ASSERT_THROWS(Equal(lhs, rhs, ctx), runtime_error);
  651.         ASSERT_THROWS(NotEqual(lhs, rhs, ctx), runtime_error);
  652.     };
  653.  
  654.     auto test_lt_uncomparable = [](const ObjectHolder& lhs, const ObjectHolder& rhs) {
  655.         DummyContext ctx;
  656.         ASSERT_THROWS(Less(lhs, rhs, ctx), runtime_error);
  657.         ASSERT_THROWS(GreaterOrEqual(lhs, rhs, ctx), runtime_error);
  658.     };
  659.  
  660.     auto test_gt_uncomparable = [](const ObjectHolder& lhs, const ObjectHolder& rhs) {
  661.         DummyContext ctx;
  662.         ASSERT_THROWS(Greater(lhs, rhs, ctx), runtime_error);
  663.         ASSERT_THROWS(LessOrEqual(lhs, rhs, ctx), runtime_error);
  664.     };
  665.  
  666.     {
  667.         test_equal(ObjectHolder::Own(Number{3}), ObjectHolder::Own(Number{3}), true);
  668.         test_equal(ObjectHolder::Own(Number{3}), ObjectHolder::Own(Number{4}), false);
  669.         test_equal(ObjectHolder::Own(Number{4}), ObjectHolder::Own(Number{3}), false);
  670.  
  671.         test_less(ObjectHolder::Own(Number{3}), ObjectHolder::Own(Number{4}), true);
  672.         test_less(ObjectHolder::Own(Number{3}), ObjectHolder::Own(Number{3}), false);
  673.         test_less(ObjectHolder::Own(Number{3}), ObjectHolder::Own(Number{2}), false);
  674.  
  675.         test_greater(ObjectHolder::Own(Number{4}), ObjectHolder::Own(Number{2}), true);
  676.         test_greater(ObjectHolder::Own(Number{3}), ObjectHolder::Own(Number{3}), false);
  677.         test_greater(ObjectHolder::Own(Number{2}), ObjectHolder::Own(Number{3}), false);
  678.  
  679.         test_eq_uncomparable(ObjectHolder::Own(Number{4}), ObjectHolder::Own(String{"4"s}));
  680.         test_eq_uncomparable(ObjectHolder::Own(Number{0}), ObjectHolder::Own(Bool{false}));
  681.  
  682.         test_lt_uncomparable(ObjectHolder::Own(Number{0}), ObjectHolder::Own(Bool{false}));
  683.         test_gt_uncomparable(ObjectHolder::Own(Number{0}), ObjectHolder::Own(String{"test"s}));
  684.     }
  685.  
  686.     {
  687.         test_equal(ObjectHolder::Own(String{""s}), ObjectHolder::Own(String{""s}), true);
  688.         test_equal(ObjectHolder::Own(String{"1"s}), ObjectHolder::Own(String{""s}), false);
  689.         test_equal(ObjectHolder::Own(String{""s}), ObjectHolder::Own(String{"1"s}), false);
  690.         test_equal(ObjectHolder::Own(String{"Hello"s}), ObjectHolder::Own(String{"Hello"s}), true);
  691.         test_equal(ObjectHolder::Own(String{"Hello"s}), ObjectHolder::Own(String{"hello"s}), false);
  692.  
  693.         test_less(ObjectHolder::Own(String{""s}), ObjectHolder::Own(String{"1"s}), true);
  694.         test_less(ObjectHolder::Own(String{"abb"s}), ObjectHolder::Own(String{"abc"s}), true);
  695.         test_less(ObjectHolder::Own(String{""s}), ObjectHolder::Own(String{""s}), false);
  696.         test_less(ObjectHolder::Own(String{"abc"s}), ObjectHolder::Own(String{"abc"s}), false);
  697.         test_less(ObjectHolder::Own(String{"abc"s}), ObjectHolder::Own(String{"abb"s}), false);
  698.  
  699.         test_greater(ObjectHolder::Own(String{"1"s}), ObjectHolder::Own(String{""s}), true);
  700.         test_greater(ObjectHolder::Own(String{"abc"s}), ObjectHolder::Own(String{"abb"s}), true);
  701.         test_greater(ObjectHolder::Own(String{""s}), ObjectHolder::Own(String{""s}), false);
  702.         test_greater(ObjectHolder::Own(String{"abc"s}), ObjectHolder::Own(String{"abc"s}), false);
  703.         test_greater(ObjectHolder::Own(String{"abb"s}), ObjectHolder::Own(String{"abc"s}), false);
  704.  
  705.         test_eq_uncomparable(ObjectHolder::Own(String{"123"s}), ObjectHolder::Own(Number{123}));
  706.         test_eq_uncomparable(ObjectHolder::Own(String{"True"s}), ObjectHolder::Own(Bool{true}));
  707.  
  708.         test_lt_uncomparable(ObjectHolder::Own(String{"123"s}), ObjectHolder::Own(Number{123}));
  709.         test_lt_uncomparable(ObjectHolder::Own(String{"True"s}), ObjectHolder::Own(Bool{true}));
  710.  
  711.         test_gt_uncomparable(ObjectHolder::Own(String{"123"s}), ObjectHolder::Own(Number{123}));
  712.         test_gt_uncomparable(ObjectHolder::Own(String{"True"s}), ObjectHolder::Own(Bool{true}));
  713.     }
  714.  
  715.     {
  716.         test_equal(ObjectHolder::Own(Bool{true}), ObjectHolder::Own(Bool{true}), true);
  717.         test_equal(ObjectHolder::Own(Bool{false}), ObjectHolder::Own(Bool{false}), true);
  718.         test_equal(ObjectHolder::Own(Bool{false}), ObjectHolder::Own(Bool{true}), false);
  719.         test_equal(ObjectHolder::Own(Bool{true}), ObjectHolder::Own(Bool{false}), false);
  720.  
  721.         test_less(ObjectHolder::Own(Bool{false}), ObjectHolder::Own(Bool{true}), true);
  722.         test_less(ObjectHolder::Own(Bool{true}), ObjectHolder::Own(Bool{true}), false);
  723.         test_less(ObjectHolder::Own(Bool{false}), ObjectHolder::Own(Bool{false}), false);
  724.         test_less(ObjectHolder::Own(Bool{true}), ObjectHolder::Own(Bool{false}), false);
  725.  
  726.         test_greater(ObjectHolder::Own(Bool{false}), ObjectHolder::Own(Bool{true}), false);
  727.         test_greater(ObjectHolder::Own(Bool{true}), ObjectHolder::Own(Bool{true}), false);
  728.         test_greater(ObjectHolder::Own(Bool{false}), ObjectHolder::Own(Bool{false}), false);
  729.         test_greater(ObjectHolder::Own(Bool{true}), ObjectHolder::Own(Bool{false}), true);
  730.  
  731.         test_eq_uncomparable(ObjectHolder::Own(Bool{true}), ObjectHolder::Own(String{"true"s}));
  732.         test_eq_uncomparable(ObjectHolder::Own(Bool{false}), ObjectHolder::Own(Number{0}));
  733.  
  734.         test_lt_uncomparable(ObjectHolder::Own(Bool{true}), ObjectHolder::Own(String{"true"s}));
  735.         test_lt_uncomparable(ObjectHolder::Own(Bool{false}), ObjectHolder::Own(Number{0}));
  736.  
  737.         test_gt_uncomparable(ObjectHolder::Own(Bool{true}), ObjectHolder::Own(String{"true"s}));
  738.         test_gt_uncomparable(ObjectHolder::Own(Bool{false}), ObjectHolder::Own(Number{0}));
  739.     }
  740.  
  741.     {
  742.         test_equal(ObjectHolder::None(), ObjectHolder::None(), true);
  743.  
  744.         test_eq_uncomparable(ObjectHolder::None(), ObjectHolder::Own(Bool{false}));
  745.         test_eq_uncomparable(ObjectHolder::None(), ObjectHolder::Own(String{"None"s}));
  746.  
  747.         test_lt_uncomparable(ObjectHolder::None(), ObjectHolder::None());
  748.         test_gt_uncomparable(ObjectHolder::None(), ObjectHolder::None());
  749.     }
  750.  
  751.     {
  752.         Closure eq_closure;
  753.         auto eq_result = ObjectHolder::Own(Bool{true});
  754.         auto eq_body = [&eq_closure, &eq_result](Closure& closure, [[maybe_unused]] Context& ctx) {
  755.             eq_closure = closure;
  756.             return eq_result;
  757.         };
  758.  
  759.         Closure lt_closure;
  760.         auto lt_result = ObjectHolder::Own(Bool{true});
  761.         auto lt_body = [&lt_closure, &lt_result](Closure& closure, [[maybe_unused]] Context& ctx) {
  762.             lt_closure = closure;
  763.             return lt_result;
  764.         };
  765.  
  766.         std::vector<Method> cls1_methods;
  767.         cls1_methods.push_back({"__eq__"s, {"rhs"s}, std::make_unique<TestMethodBody>(eq_body)});
  768.         cls1_methods.push_back({"__lt__"s, {"rhs"s}, std::make_unique<TestMethodBody>(lt_body)});
  769.         Class cls1{"Class1"s, std::move(cls1_methods), nullptr};
  770.         ClassInstance lhs{cls1};
  771.  
  772.         Class cls2{"Class2"s, {}, nullptr};
  773.         ClassInstance rhs{cls2};
  774.  
  775.         eq_result = ObjectHolder::Own(Bool{true});
  776.         test_equal(ObjectHolder::Share(lhs), ObjectHolder::Share(rhs), true);
  777.         ASSERT(eq_closure.at("self"s).TryAs<ClassInstance>() == &lhs);
  778.         ASSERT(eq_closure.at("rhs"s).TryAs<ClassInstance>() == &rhs);
  779.         ASSERT(lt_closure.empty());
  780.         eq_result = ObjectHolder::Own(Bool{false});
  781.         test_equal(ObjectHolder::Share(lhs), ObjectHolder::Share(rhs), false);
  782.         eq_closure.clear();
  783.         lt_closure.clear();
  784.  
  785.         eq_result = ObjectHolder::Own(Bool{false});
  786.         lt_result = ObjectHolder::Own(Bool{true});
  787.         test_less(ObjectHolder::Share(lhs), ObjectHolder::Share(rhs), true);
  788.         ASSERT(lt_closure.at("self"s).TryAs<ClassInstance>() == &lhs);
  789.         ASSERT(lt_closure.at("rhs"s).TryAs<ClassInstance>() == &rhs);
  790.         ASSERT(eq_closure.empty());
  791.         eq_result = ObjectHolder::Own(Bool{true});
  792.         lt_result = ObjectHolder::Own(Bool{false});
  793.         test_less(ObjectHolder::Share(lhs), ObjectHolder::Share(rhs), false);
  794.         eq_closure.clear();
  795.         lt_closure.clear();
  796.  
  797.         eq_result = ObjectHolder::Own(Bool{false});
  798.         lt_result = ObjectHolder::Own(Bool{false});
  799.         test_greater(ObjectHolder::Share(lhs), ObjectHolder::Share(rhs), true);
  800.         ASSERT(eq_closure.at("self"s).TryAs<ClassInstance>() == &lhs);
  801.         ASSERT(eq_closure.at("rhs"s).TryAs<ClassInstance>() == &rhs);
  802.         ASSERT(lt_closure.at("self"s).TryAs<ClassInstance>() == &lhs);
  803.         ASSERT(lt_closure.at("rhs"s).TryAs<ClassInstance>() == &rhs);
  804.         eq_result = ObjectHolder::Own(Bool{true});
  805.         lt_result = ObjectHolder::Own(Bool{true});
  806.         test_greater(ObjectHolder::Share(lhs), ObjectHolder::Share(rhs), false);
  807.     }
  808. }
  809.  
  810. void TestClass() {
  811.     vector<Method> methods;
  812.     Closure* passed_closure = nullptr;
  813.     Context* passed_context = nullptr;
  814.     auto body = [&passed_closure, &passed_context](Closure& closure, Context& ctx) {
  815.         passed_closure = &closure;
  816.         passed_context = &ctx;
  817.         return ObjectHolder::Own(Number{42});
  818.     };
  819.     methods.push_back({"method"s, {"arg1"s, "arg2"s}, make_unique<TestMethodBody>(body)});
  820.     Class cls{"Test"s, move(methods), nullptr};
  821.     ASSERT_EQUAL(cls.GetName(), "Test"s);
  822.     ASSERT_EQUAL(cls.GetMethod("missing_method"s), nullptr);
  823.  
  824.     const Method* method = cls.GetMethod("method"s);
  825.     ASSERT(method != nullptr);
  826.     DummyContext ctx;
  827.     Closure closure;
  828.     auto result = method->body->Execute(closure, ctx);
  829.     ASSERT_EQUAL(passed_context, &ctx);
  830.     ASSERT_EQUAL(passed_closure, &closure);
  831.     const Number* returned_number = result.TryAs<Number>();
  832.     ASSERT(returned_number != nullptr && returned_number->GetValue() == 42);
  833.  
  834.     ostringstream out;
  835.     cls.Print(out, ctx);
  836.     ASSERT(ctx.output.str().empty());
  837.     ASSERT_EQUAL(out.str(), "Class Test"s);
  838. }
  839.  
  840. void TestClassInstance() {
  841.     vector<Method> methods;
  842.  
  843.     Closure passed_closure;
  844.     auto str_body = [&passed_closure](Closure& closure, [[maybe_unused]] Context& ctx) {
  845.         passed_closure = closure;
  846.         return ObjectHolder::Own(String{"result"s});
  847.     };
  848.  
  849.     methods.push_back({"__str__", {}, make_unique<TestMethodBody>(str_body)});
  850.  
  851.     Class cls{"Test"s, move(methods), nullptr};
  852.     ClassInstance instance{cls};
  853.  
  854.     ASSERT_EQUAL(&instance.Fields(), &const_cast<const ClassInstance&>(instance).Fields());
  855.     ASSERT(instance.HasMethod("__str__"s, 0));
  856.  
  857.     ostringstream out;
  858.     DummyContext ctx;
  859.     instance.Print(out, ctx);
  860.     ASSERT_EQUAL(out.str(), "result"s);
  861.  
  862.     ASSERT_THROWS(instance.Call("missing_method"s, {}, ctx), runtime_error);
  863. }
  864.  
  865. }//end namespace
  866.  
  867. void RunObjectsTests(TestRunner& tr) {
  868.     RUN_TEST(tr, runtime::TestNumber);
  869.     RUN_TEST(tr, runtime::TestString);
  870.     RUN_TEST(tr, runtime::TestBool);
  871.     RUN_TEST(tr, runtime::TestMethodInvocation);
  872.     RUN_TEST(tr, runtime::TestIsTrue);
  873.     RUN_TEST(tr, runtime::TestComparison);
  874.     RUN_TEST(tr, runtime::TestClass);
  875.     RUN_TEST(tr, runtime::TestClassInstance);
  876. }
  877.  
  878. void RunObjectHolderTests(TestRunner& tr) {
  879.     RUN_TEST(tr, runtime::TestNonowning);
  880.     RUN_TEST(tr, runtime::TestOwning);
  881.     RUN_TEST(tr, runtime::TestMove);
  882.     RUN_TEST(tr, runtime::TestNullptr);
  883. }
  884.  
  885. }//end namespace runtime
  886. -----------------------------------------------------------------------
  887. test_runner_p.h
  888. -----------------------------------------------------------------------
  889. #pragma once
  890.  
  891. #include <iostream>
  892. #include <map>
  893. #include <set>
  894. #include <sstream>
  895. #include <stdexcept>
  896. #include <string>
  897. #include <unordered_map>
  898. #include <vector>
  899.  
  900. namespace TestRunnerPrivate {
  901. template <class Map>
  902. std::ostream& PrintMap(std::ostream& os, const Map& m) {
  903.     os << "{";
  904.     bool first = true;
  905.     for (const auto& kv : m) {
  906.         if (!first) {
  907.             os << ", ";
  908.         }
  909.         first = false;
  910.         os << kv.first << ": " << kv.second;
  911.     }
  912.     return os << "}";
  913. }
  914.  
  915. }//end namespace TestRunnerPrivate
  916.  
  917. template <class T>
  918. std::ostream& operator<<(std::ostream& os, const std::vector<T>& s) {
  919.     os << "{";
  920.     bool first = true;
  921.     for (const auto& x : s) {
  922.         if (!first) {
  923.             os << ", ";
  924.         }
  925.         first = false;
  926.         os << x;
  927.     }
  928.     return os << "}";
  929. }
  930.  
  931. template <class T>
  932. std::ostream& operator<<(std::ostream& os, const std::set<T>& s) {
  933.     os << "{";
  934.     bool first = true;
  935.     for (const auto& x : s) {
  936.         if (!first) {
  937.             os << ", ";
  938.         }
  939.         first = false;
  940.         os << x;
  941.     }
  942.     return os << "}";
  943. }
  944.  
  945. template <class K, class V>
  946. std::ostream& operator<<(std::ostream& os, const std::map<K, V>& m) {return TestRunnerPrivate::PrintMap(os, m);}
  947.  
  948. template <class K, class V>
  949. std::ostream& operator<<(std::ostream& os, const std::unordered_map<K, V>& m) {return TestRunnerPrivate::PrintMap(os, m);}
  950.  
  951. template <class T, class U>
  952. void AssertEqual(const T& t, const U& u, const std::string& hint = {}) {
  953.     if (!(t == u)) {
  954.         std::ostringstream os;
  955.         os << "Assertion failed: " << t << " != " << u;
  956.         if (!hint.empty()) {
  957.             os << " hint: " << hint;
  958.         }
  959.         throw std::runtime_error(os.str());
  960.     }
  961. }
  962.  
  963. inline void Assert(bool b, const std::string& hint) {
  964.     AssertEqual(b, true, hint);
  965. }
  966.  
  967. class TestRunner {
  968. public:
  969.     template <class TestFunc>
  970.     void RunTest(TestFunc func, const std::string& test_name) {
  971.         try {
  972.             func();
  973.             std::cerr << test_name << " OK" << std::endl;
  974.         } catch (std::exception& e) {
  975.             ++fail_count;
  976.             std::cerr << test_name << " fail: " << e.what() << std::endl;
  977.         } catch (...) {
  978.             ++fail_count;
  979.             std::cerr << "Unknown exception caught" << std::endl;
  980.         }
  981.     }
  982.  
  983.     ~TestRunner() {
  984.         std::cerr.flush();
  985.         if (fail_count > 0) {
  986.             std::cerr << fail_count << " unit tests failed. Terminate" << std::endl;
  987.             exit(1);
  988.         }
  989.     }
  990.  
  991. private:
  992.     int fail_count = 0;
  993. };
  994.  
  995. #ifndef FILE_NAME
  996. #define FILE_NAME __FILE__
  997. #endif
  998.  
  999. #define ASSERT_EQUAL(x, y)                                                                       \
  1000.     {                                                                                            \
  1001.         std::ostringstream __assert_equal_private_os;                                            \
  1002.         __assert_equal_private_os << #x << " != " << #y << ", " << FILE_NAME << ":" << __LINE__; \
  1003.         AssertEqual(x, y, __assert_equal_private_os.str());                                      \
  1004.     }
  1005.  
  1006. #define ASSERT(x)                                                                   \
  1007.     {                                                                               \
  1008.         std::ostringstream __assert_private_os;                                     \
  1009.         __assert_private_os << #x << " is false, " << FILE_NAME << ":" << __LINE__; \
  1010.         Assert(static_cast<bool>(x), __assert_private_os.str());                    \
  1011.     }
  1012.  
  1013. #define RUN_TEST(tr, func) tr.RunTest(func, #func)
  1014.  
  1015. #define ASSERT_THROWS(expr, expected_exception)                                                   \
  1016.     {                                                                                             \
  1017.         bool __assert_private_flag = true;                                                        \
  1018.         try {                                                                                     \
  1019.             expr;                                                                                 \
  1020.             __assert_private_flag = false;                                                        \
  1021.         } catch (expected_exception&) {                                                           \
  1022.         } catch (...) {                                                                           \
  1023.             std::ostringstream __assert_private_os;                                               \
  1024.             __assert_private_os << "Expression " #expr                                            \
  1025.                                    " threw an unexpected exception"                               \
  1026.                                    " " FILE_NAME ":"                                              \
  1027.                                 << __LINE__;                                                      \
  1028.             Assert(false, __assert_private_os.str());                                             \
  1029.         }                                                                                         \
  1030.         if (!__assert_private_flag) {                                                             \
  1031.             std::ostringstream __assert_private_os;                                               \
  1032.             __assert_private_os << "Expression " #expr                                            \
  1033.                                    " is expected to throw " #expected_exception " " FILE_NAME ":" \
  1034.                                 << __LINE__;                                                      \
  1035.             Assert(false, __assert_private_os.str());                                             \
  1036.         }                                                                                         \
  1037.     }
  1038.  
  1039. #define ASSERT_DOESNT_THROW(expr)                               \
  1040.     try {                                                       \
  1041.         expr;                                                   \
  1042.     } catch (...) {                                             \
  1043.         std::ostringstream __assert_private_os;                 \
  1044.         __assert_private_os << "Expression " #expr              \
  1045.                                " threw an unexpected exception" \
  1046.                                " " FILE_NAME ":"                \
  1047.                             << __LINE__;                        \
  1048.         Assert(false, __assert_private_os.str());               \
  1049.     }
  1050.  
  1051. #define EOF_GUARD
Advertisement
Add Comment
Please, Sign In to add comment