reveal.js

repository·master·Indexed 43 days ago

https://github.com/cpp-testing/gunit

An HTML presentation framework for creating slides with nested layouts, Markdown support, and PDF export. Version 3.2.0 includes a JavaScript API for programmatic control, a system for custom Sass themes, and features for speaker notes and background configurations.

Tokens
17.6K
Snippets
66
Records
77
Agent score
53%

What's inside reveal.js

  1. Use GUnit.GMock to automate mock generation

    master

    GUnit.GMock allows you to use GoogleMock features without manually writing and maintaining mock classes. It works by wrapping an abstract interface in a GMock<T> template.

    Key Features

    • Automatic Mocking: No need to define MOCK_METHOD for every interface.
    • Compatibility: Works alongside traditional GoogleMock mocks.
    • Mock Types: Supports NaggyGMock (default), StrictGMock, and NiceGMock.
    • Syntax Note: When using EXPECT_CALL or ON_CALL with GUnit.GMock, you must wrap the function name in additional parentheses to handle the macro expansion correctly.

    Supported Macros

    • EXPECT_CALL(mock, (function)(args))
    • ON_CALL(mock, (function)(args))
    • EXPECT_INVOKE(mock, function, args) (Universal syntax that works with both GoogleMock and GUnit.GMock)
    // GoogleMock style
    EXPECT_CALL(mock, function(42)).WillOnce(Return(true));
    
    // GUnit.GMock style (requires extra parens)
    EXPECT_CALL(mock, (function)(42)).WillOnce(Return(true));
    
    // Universal GUnit.GMock style
    EXPECT_INVOKE(mock, function, 42); // Works for both
    
    // ON_CALL style
    ON_CALL(mock, (function)()).WillByDefault(Return(true));
  2. Use GStep table parameters

    master

    When a Gherkin step includes a data table, you can capture it in your lambda using the Table type (which is an alias for table<unordered_map<string, convertible>>).

    Each value in the table is wrapped in a convertible object. You can:

    • Use operator T() to implicitly convert the value to a specific type.
    • Call .available() to check if a field was actually set in the table.
  3. Implement BDD scenarios with GUnit.GSteps

    master

    GUnit.GSteps provides support for Gherkin-style Behaviour Driven Development (BDD). You define feature files in .feature format and implement the steps in C++ using the GSTEPS macro. Steps are matched using string patterns (e.g., {n} for numbers).

    // Test/Features/Calc/Steps/CalcSteps.cpp
    #include <GUnit.h>
    
    GSTEPS("Calc*") {
      auto result = 0;
    
      Given("I created a calculator with value {n}") = [&](int n) {
        Calculator calc{n};
    
        Given("I have entered {n} into the calculator") = [&](int n) {
          calc.push(n);
        };
    
        When("I press add") = [&] {
          result = calc.add();
        };
    
        Then("The result should be {expected}") = [&](int expected) {
           EXPECT_EQ(expected, result);
        };
      };
    }
  4. How Multiplexing works

    master

    The Multiplex plugin allows an audience to follow a master presentation in real-time on their own devices. It requires three components:

    1. Master presentation: The controller (usually run locally by the presenter).
    2. Client presentations: The followers (hosted on a public static file server).
    3. Socket.io server: The broadcaster that relays events from the master to the clients.

    To use it, you must generate a unique secret and id from your Socket.io server's token endpoint (e.g., http://your-server/token).

  5. Use GUnit.GMake to simplify SUT and mock creation

    master

    GUnit.GMake is a utility designed to remove boilerplate mock declarations and decouple tests from the System Under Test (SUT) constructor. It allows you to create the SUT and its required mocks in a single call, ensuring that if the SUT's constructor changes (e.g., argument order or type), your test cases do not need to be refactored.

    Key Benefits

    • Automatic Mock Creation: Required mocks are instantiated automatically based on the SUT's constructor requirements.
    • Constructor Resilience: Tests remain valid even if the SUT constructor is refactored (e.g., changing from shared_ptr to raw pointers or changing argument order).
    • Reduced Boilerplate: Eliminates the need to manually declare and inject mocks for every test.
    // Example of the core pattern
    auto [sut, mocks] = testing::make<example, NaggyMock>();
  6. Use Speaker Notes

    master

    The speaker notes plugin allows you to present per-slide notes in a separate browser window (opened via the »S« key).

    Defining Notes:

    1. HTML <aside> element: Append an <aside class="notes"> inside a <section>. You can use the data-markdown attribute on the aside to write notes in Markdown.
    2. data-notes attribute: Add notes directly to the section: <section data-notes="Your notes here"></section>.
    3. Markdown delimiter: If using the external Markdown plugin, use a special delimiter (e.g., Note:) defined in your data-separator-notes configuration.

    Configuration & Sharing:

    • showNotes: Set to true in the configuration to make notes visible to everyone at the bottom of the presentation. This also includes them in PDF exports.
    • showNotes: "separate-page": When exporting to PDF, this prints notes on a separate page following the slide instead of in a semi-transparent box on top of the slide.
    • Pacing Timer: To enable a pacing timer in the speaker view, configure the defaultTiming parameter in the Reveal configuration block (value in seconds). You can also set per-slide timing using the data-timing attribute on a <section>.
    <section>
    	<h2>Some Slide</h2>
    
    	<aside class="notes">
    		Oh hey, these are some notes. They'll be hidden in your presentation, but you can see them if you open the speaker notes window (hit »S« on your keyboard).
    	</aside>
    </section>
  7. How to grant test access to private class members

    master

    If you need to test private or protected members of a class using GUnit, you can use the friend keyword to grant the test class access. There are three primary ways to achieve this:

    1. Using the class name directly: If your test is defined as GTEST(SomeTest), you can declare the test as a friend using the template syntax friend struct GTEST<SomeTest, testing::detail::string<> >;.
    2. Using string literals (cumbersome): You can declare friendship using the string-based test name, but this requires manually expanding the string into a testing::detail::string type.
    3. Using the FRIEND_GTEST macro: This is the recommended way to grant friendship using a string name. It uses GUnit's internal preprocessor magic to map the string name to the correct GTEST type.

    Note: Avoid the practice of using #define private public before including production headers, as it is considered bad practice.

    #include <GUnit/Detail/Preprocessor.h>
    #include <GUnit/Detail/StringUtils.h>
    
    #define FRIEND_GTEST(name) \
    struct __GUNIT_CAT(GTEST_STRING_, __LINE__) { static constexpr const char* chrs = #name; }; \
    friend struct GTEST<decltype(::make_string<__GUNIT_CAT(GTEST_STRING_, __LINE__), sizeof(#name)>::type()), ::string<>>;
    
    class SomeClass {
        FRIEND_GTEST("SomeTest")
    };
    
    GTEST("SomeTest") { ... }
  8. Create multiple sub-tests within a single GTEST block using SHOULD

    master

    Instead of defining multiple TEST_F macros, you can use a single GTEST block with a fixture and define multiple sub-tests using the SHOULD macro. This is particularly useful when testing multiple scenarios for the same System Under Test (SUT) and Mocks.

    Note: When using SHOULD, the fixture's SetUp() and TearDown() methods are called separately for each SHOULD block.

    Filtering sub-tests: To run a specific SHOULD test case via the command line, use a colon (:) in the --gtest_filter flag.

    • FooTest*:Do A : Runs FooTest where the SHOULD clause matches "Do A".
    • FooTest*:Do* : Runs all SHOULD clauses in FooTest starting with "Do".
    • FooTest.:Do* : Alternative syntax for matching SHOULD clauses.
    struct FooTest : testing::Test {
      void SetUp() override { /* setup logic */ }
      void TearDown() override { /* teardown logic */ }
    };
    
    GTEST(FooTest) {
      // This is sub-test 1
      SHOULD("call foo") {
        // ...
      }
    
      // This is sub-test 2
      SHOULD("call foo and return 0") {
        // ...
      }
    }
  9. Understand the reveal.js folder structure

    master

    The project follows this directory structure:

    • css/: Core styles required for the project to function.
    • js/: Core JavaScript files required for the project to function.
    • plugin/: Extensions and components developed for reveal.js.
    • lib/: Third-party assets including JavaScript, CSS, and fonts.
  10. How Multiplexing works in reveal.js

    master

    The Multiplex plugin allows an audience to view slides on their own devices in real time as the presenter navigates. It requires three components:

    1. Master presentation: The presenter's controlled view.
    2. Client presentations: The audience's view that follows the master.
    3. Socket.io server: A central server that broadcasts slideChanged events from the master to all clients.

    To use a hosted Socket.io server, you must generate a unique secret and id by visiting [YOUR_SOCKET_IO_SERVER_URL]/token.

    // Concept: Master controls, Clients follow
    // Master needs: secret, id, url
    // Client needs: id, url (secret is null)
  11. Build libgherkin-cpp

    master

    Before using GUnit.GSteps, you must build the underlying Gherkin library. Navigate to the library directory and run make lib to generate the static (.a) and shared (.so) libraries.

    $cd libs/gherkin-cpp && make lib
    $ls libs/gherkin-cpp
      libgherkin-cpp.a
      libgherkin-cpp.so