Skip to content

krzysztof-jusiak/vc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Boost Licence


Virtual Concepts

Concept

template<class T>
const auto Equality_comparable =
  $requires(T)(auto a, auto b) (
    bool(a == b),
    bool(a != b)
  );
template<class T>
const auto Iterator() {
  return CopyConstructible<T> &&
         CopyAssignable<T> &&
         Destructible<T> &&
         $requires(T)(auto&& t) (
           *t,
           typename decltype(t)::type
         );
  }
}
template<class T, class F, class R, class... Ts>
const auto Callable(F f) {
  return $requires(T)(auto&& t, Ts... args) (
    R((t.*f)(args...));
  )
}
template<class T, class R, class... Ts>
const auto Creatable = Callable<T, R(Ts...)>($(create));
struct Readable {
  template<class T>
  auto operator()() {
    return CopyConstructible() &&
       $requires(T)(auto&& t, std::ostream& os) (
          os = (os << t)
       ) &&
       Callable<T, void(int)>($(read));
  }
};

Implementation

struct FileReader {
  void read(int) const {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
  }
};

std::ostream& operator<<(std::ostream& os, FileReader&) {
  return os;
}

Usage

int main() {
  // constraint checking
  static_assert(Equality_comparable<int>, "");
  static_assert(Readable{}.operator()<FileReader>(), "");
  
  // template mocking
  testing::GMock<Readable> mockReadable;
  EXPECT_CALL(mockReadable, read, 42);
  mockReadable.read(42);
  
  // type erasure - dynamic dispatch
  type_erasure::any<Readable> readable = FileReader{};
  readable.read(42);
  
  // type erasure mocking
  readable = GMock<Readable>{};
  EXPECT_CALL(mock, read, 42);
  readable.read(42);
}

Dependency Injection - [Boost].DI

template<class TReader = Readable> // = 'Concept'
class App {
  TReader reader;                       // static dispatch
  type_erasure::any<Printable> printer; // dynamic dispatch
  
public:
  App(TReader reader, type_erasure::any<Printable> printer)
   : reader(reader), printer(printer)
  { }
  
  void run() {
    printer.print(reader.read());
  }
};

int main() {
  const auto injector = di::make_injector(
     di::bind<Readable>.to<FileReader>()
     di::bind<Printable>.to<ConsolePrinter>()
  );
  
  injector.create<App>().run();
}

Testing

"should print read text"_test = [] {
  constexpr auto value = 42;

  auto [sut, mocks] = testing::make<App>(); // creates System Under Test
                                            // and Mocks

  InSequence sequence;
  EXPECT_CALL(mocks<Readable>(), read).WillOnce(Return(value));
  EXPECT_CALL(mocks<Printable>(), print, value);

  sut.run();
};

Dependencies

References