Skip to content

Latest commit

 

History

History
406 lines (335 loc) · 9.25 KB

216.md

File metadata and controls

406 lines (335 loc) · 9.25 KB
Info

Example

template<class T>
struct singleton {
  static auto& get() {
    static T s{};
    return s;
  }
};

class api {
 public:
  virtual ~api() = default;
  virtual auto call() const -> int { return 42; }
};

class app {
 public:
  auto run() -> int {
    return singleton<api>::get().call();
  }
};

class app_di {
 public:
  constexpr explicit(true) app_di(const api& api)
    : api_{api}
  { }

  auto run() const -> int {
    return api_.call();
  }

 private:
  const api& api_;
};

int main() {
  {
    app a{}; // coupled
    assert(42 == a.run());
  }

  {
    app_di a{singleton<api>::get()}; // injected
    assert(42 == a.run())
  }

  {
    struct : api {
      auto call() const -> int override { return 43; }
    } fake_api{};

    app_di api{fake_api}; // faked
    assert(43 == api.run());
  }
}

https://godbolt.org/z/Phb9YE

Puzzle

  • Can you implement required steps and the app to satisfy feature tests?

    • NOTE: Feature test must remain as authored
template <class T>
struct singleton {
  static auto& get() {
    static T s{};
    return s;
  }
};

class api {
 public:
  virtual ~api() = default;
  virtual auto call() const -> int { return {}; }
};

class app; //TODO

int main() {
  using namespace boost::ut;

  bdd::gherkin::steps steps = [](auto& steps) {
    steps.feature("Singleton") = [&] {
      steps.scenario("*") = [&] {
        steps.given("I have an app") = [&] {
          // TODO

          steps.given("I have an fake_api which returns {}") = [&](int value) {
            // TODO

            auto run_result = 0;
            steps.when("I call run on the app") = [&] {
              // TODO
            };

            steps.then("I should get {}") = [&](_i result) {
              expect(run_result == result);
            };
          };
        };
      };
    };
  };

  // Feature tests must remain as authored
  "app"_test = steps | R"(
      Feature: Singleton

        Scenario: Dependency Injection
          Given I have an app
          Given I have an fake_api which returns 42
           When I call run on the app
           Then I should get 42

        Scenario: Dependency Injection
          Given I have an app
          Given I have an fake_api which returns 100
           When I call run on the app
           Then I should get 100
    )";
}

https://godbolt.org/z/xdq4WY

Solutions

bdd::gherkin::steps steps = [](auto& steps) {
  steps.feature("Singleton") = [&] {
    steps.scenario("*") = [&] {
      steps.given("I have an app") = [&] {
        std::unique_ptr<app> app{};

        steps.given("I have an fake_api which returns {}") = [&](int value) {
          auto api = fake_api{value};
          app = std::make_unique<class app>(api);

          auto run_result = 0;
          steps.when("I call run on the app") = [&] {
            run_result = app->run();
          };

          steps.then("I should get {}") = [&](_i result) {
            expect(run_result == result);
          };
        };
      };
    };
  };
};

https://godbolt.org/z/cz5s8q

bdd::gherkin::steps steps = [](auto& steps) {
  steps.feature("Singleton") = [&] {
    steps.scenario("*") = [&] {
      steps.given("I have an fake_api which returns {}") = [&](int value) {
        auto api = fake_api{value};
        steps.given("I have an app") = [&] {
          app app{api};
          auto run_result = 0;
          steps.when("I call run on the app") = [&] {
            run_result = app.run();
          };
          steps.then("I should get {}") = [&](_i result) {
            expect(run_result == result);
          };
        };
      };
    };
  };
};

https://godbolt.org/z/xo8TsP

bdd::gherkin::steps steps = [](auto& steps) {
  steps.feature("Singleton") = [&] {
    steps.scenario("*") = [&] {
      steps.given("I have an app") = [&] {
        app sut{};

        steps.given("I have an fake_api which returns {}") = [&](int value) {
          struct fake : api {
              fake(int value) : value(value), api{} {};
              int value{};
               auto call() const -> int override {
                  return value;
              }
          } fake_api{ value };
          singleton<api*>::get() = &fake_api;

          auto run_result = 0;
          steps.when("I call run on the app") = [&] {
            run_result = sut.run();
          };

          steps.then("I should get {}") = [&](_i result) {
            expect(run_result == result);
          };
        };
      };
    };
  };
};

https://godbolt.org/z/T69oEW

bdd::gherkin::steps steps = [](auto& steps) {
  steps.feature("Singleton") = [&] {
    steps.scenario("*") = [&] {
      steps.given("I have an fake_api which returns {}") = [&](int value) {
        class FakeApi : public api {
          using value_t = int;

         public:
          constexpr FakeApi(const value_t val) : value(val) {}
          value_t call() const override { return value; }

         private:
          value_t value;
        } fake_api{value};

        steps.given("I have an app") = [&] {
          app app{fake_api};

          auto run_result = 0;
          steps.when("I call run on the app") = [&] {
            run_result = app.run();
          };

          steps.then("I should get {}") = [&](_i result) {
            expect(run_result == result);
          };
        };
      };
    };
  };
};

https://godbolt.org/z/MeexbT

bdd::gherkin::steps steps = [](auto& steps) {
  steps.feature("Singleton") = [&] {
    steps.scenario("*") = [&] {
      steps.given("I have an fake_api which returns {}") = [&](int value) {
        struct fake_api {
          auto call() const -> int { return value_; }
          auto set(int i) -> void { value_ = i; }
          int value_;
        };
        singleton<fake_api>::get().set(value);
        steps.given("I have an app") = [&] {
          app<fake_api> app;
          auto run_result = 0;
          steps.when("I call run on the app") = [&] {
            run_result = app.run();
          };
          steps.then("I should get {}") = [&](_i result) {
            expect(run_result == result);
          };
        };
      };
    };
  };
};

https://godbolt.org/z/jsn6G9

bdd::gherkin::steps steps = [](auto& steps) {
  steps.feature("Singleton") = [&] {
    steps.scenario("*") = [&] {
      steps.given("I have an app") = [&] {
        app my_app{};

        steps.given("I have an fake_api which returns {}") = [&](int value) {
          singleton<fake_api>::get().value = value;

          auto run_result = 0;
          steps.when("I call run on the app") = [&] {
            run_result = my_app.run();
          };

          steps.then("I should get {}") = [&](_i result) {
            expect(run_result == result);
          };
        };
      };
    };
  };
};

https://godbolt.org/z/3n8bPv

bdd::gherkin::steps steps = [](auto& steps) {
  steps.feature("Singleton") = [&] {
    steps.scenario("*") = [&] {
      steps.given("I have an fake_api which returns {}") = [&](int value) {
        class fakeapi : public api {
           public:

           void set(const int value) { value_ = value; }
           auto call() const -> int override { return value_; }

           private:
            int value_;
        };

        singleton<fakeapi>().get().set(value);

        steps.given("I have an app") = [&] {
          singleton<app>().get().set(&singleton<fakeapi>().get());

          auto run_result = 0;
          steps.when("I call run on the app") = [&] {
            run_result = singleton<app>().get().run();
          };

          steps.then("I should get {}") = [&](_i result) {
            expect(run_result == result);
          };
        };
      };
    };
  };
};

https://godbolt.org/z/7T3cnj

bdd::gherkin::steps steps = [](auto& steps) {
  steps.feature("Singleton") = [&] {
    steps.scenario("*") = [&] {
      steps.given("I have an fake_api which returns {}") = [&](int value) {
        apiI api1(value);
        steps.given("I have an app") = [&] {
          app myApp(api1);
          auto run_result = 0;
          steps.when("I call run on the app") = [&] {
             run_result = myApp.run();
          };
          steps.then("I should get {}") = [&](_i result) {
            expect(run_result == result);
          };
        };
      };
    };
  };
};

https://godbolt.org/z/q9Mo7o

bdd::gherkin::steps steps = [](auto& steps) {
  steps.feature("Singleton") = [&] {
    steps.scenario("*") = [&] {
      steps.given("I have an fake_api which returns {}") = [&](int value) {
        singleton<fake_api>::get().value = value;

        steps.given("I have an app") = [&] {
          app a{singleton<fake_api>::get()};

          auto run_result = 0;
          steps.when("I call run on the app") = [&] {
            run_result = a.run();
          };

          steps.then("I should get {}") = [&](_i result) {
            expect(run_result == result);
          };
        };
      };
    };
  };
};

https://godbolt.org/z/fjzrfd