Skip to content

Commit 07a77d7

Browse files
committed
add examples-tables-attachment compatibility test
1 parent 6f1f4c8 commit 07a77d7

File tree

15 files changed

+1016
-21
lines changed

15 files changed

+1016
-21
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include "cucumber_cpp/CucumberCpp.hpp"
2+
#include <cstdio>
3+
#include <filesystem>
4+
#include <fstream>
5+
#include <iostream>
6+
#include <source_location>
7+
#include <string>
8+
9+
namespace
10+
{
11+
const std::filesystem::path currentCompileDir = std::filesystem::path{ std::source_location::current().file_name() }.parent_path();
12+
}
13+
14+
WHEN(R"(a JPEG image is attached)")
15+
{
16+
std::ifstream jpegFile{ currentCompileDir / "cucumber.jpeg", std::ios::binary };
17+
Attach(jpegFile, "image/jpeg");
18+
}
19+
20+
WHEN(R"(a PNG image is attached)")
21+
{
22+
std::ifstream pngFile{ currentCompileDir / "cucumber.png", std::ios::binary };
23+
Attach(pngFile, "image/png");
24+
}

cucumber_cpp/library/StepRegistry.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
#include "cucumber_cpp/library/Context.hpp"
1111
#include "cucumber_cpp/library/cucumber_expression/Matcher.hpp"
1212
#include "cucumber_cpp/library/cucumber_expression/ParameterRegistry.hpp"
13+
#include "cucumber_cpp/library/engine/ExecutionContext.hpp"
1314
#include "cucumber_cpp/library/engine/StepType.hpp"
15+
#include "cucumber_cpp/library/util/Broadcaster.hpp"
1416
#include <any>
1517
#include <cstddef>
1618
#include <cstdint>
@@ -29,13 +31,12 @@
2931

3032
namespace cucumber_cpp::library
3133
{
32-
33-
using StepFactory = std::unique_ptr<Body> (&)(Context&, std::optional<std::span<const cucumber::messages::pickle_table_row>>, const std::optional<cucumber::messages::pickle_doc_string>&);
34+
using StepFactory = std::unique_ptr<Body> (&)(util::Broadcaster& broadCaster, Context&, engine::StepOrHookStarted stepOrHookStarted, std::optional<std::span<const cucumber::messages::pickle_table_row>>, const std::optional<cucumber::messages::pickle_doc_string>&);
3435

3536
template<class T>
36-
std::unique_ptr<Body> StepBodyFactory(Context& context, std::optional<std::span<const cucumber::messages::pickle_table_row>> table, const std::optional<cucumber::messages::pickle_doc_string>& docString)
37+
std::unique_ptr<Body> StepBodyFactory(util::Broadcaster& broadCaster, Context& context, engine::StepOrHookStarted stepOrHookStarted, std::optional<std::span<const cucumber::messages::pickle_table_row>> table, const std::optional<cucumber::messages::pickle_doc_string>& docString)
3738
{
38-
return std::make_unique<T>(context, table, docString);
39+
return std::make_unique<T>(broadCaster, context, stepOrHookStarted, table, docString);
3940
}
4041

4142
struct StepMatch

cucumber_cpp/library/engine/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
add_library(cucumber_cpp.library.engine STATIC ${CCR_EXCLUDE_FROM_ALL})
22

33
target_sources(cucumber_cpp.library.engine PRIVATE
4+
ExecutionContext.cpp
5+
ExecutionContext.hpp
46
Step.cpp
57
Step.hpp
68
StepType.hpp
@@ -12,6 +14,7 @@ target_include_directories(cucumber_cpp.library.engine PUBLIC
1214
)
1315

1416
target_link_libraries(cucumber_cpp.library.engine PUBLIC
17+
base64
1518
cucumber_cpp.library
1619
cucumber_cpp.library.util
1720
cucumber_cpp.library.cucumber_expression
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#include "cucumber_cpp/library/engine/ExecutionContext.hpp"
2+
#include "base64.hpp"
3+
#include "cucumber/messages/attachment.hpp"
4+
#include "cucumber/messages/attachment_content_encoding.hpp"
5+
#include "cucumber/messages/test_run_hook_started.hpp"
6+
#include "cucumber/messages/test_step_started.hpp"
7+
#include "cucumber_cpp/CucumberCpp.hpp"
8+
#include "cucumber_cpp/library/support/Timestamp.hpp"
9+
#include "cucumber_cpp/library/util/Broadcaster.hpp"
10+
#include <istream>
11+
#include <iterator>
12+
#include <optional>
13+
#include <string>
14+
#include <utility>
15+
#include <variant>
16+
17+
namespace cucumber_cpp::library::engine
18+
{
19+
namespace
20+
{
21+
constexpr auto LogMediaType{ "text/x.cucumber.log+plain" };
22+
constexpr auto LinkMediaType{ "text/uri-list" };
23+
24+
std::pair<std::optional<std::string>, std::optional<std::string>> ReadTestStepStartedIds(StepOrHookStarted stepOrHookStarted)
25+
{
26+
if (std::holds_alternative<cucumber::messages::test_step_started>(stepOrHookStarted))
27+
{
28+
return {
29+
std::get<cucumber::messages::test_step_started>(stepOrHookStarted).test_case_started_id,
30+
std::get<cucumber::messages::test_step_started>(stepOrHookStarted).test_step_id,
31+
};
32+
}
33+
34+
return {};
35+
}
36+
37+
std::pair<std::optional<std::string>, std::optional<std::string>> ReadTestRunHookStartedIds(StepOrHookStarted stepOrHookStarted)
38+
{
39+
if (std::holds_alternative<cucumber::messages::test_run_hook_started>(stepOrHookStarted))
40+
{
41+
return {
42+
std::get<cucumber::messages::test_run_hook_started>(stepOrHookStarted).test_run_started_id,
43+
std::get<cucumber::messages::test_run_hook_started>(stepOrHookStarted).id,
44+
};
45+
}
46+
47+
return {};
48+
}
49+
}
50+
51+
ExecutionContext::ExecutionContext(util::Broadcaster& broadCaster, Context& context, StepOrHookStarted stepOrHookStarted)
52+
: context{ context }
53+
, broadCaster{ broadCaster }
54+
, stepOrHookStarted{ std::move(stepOrHookStarted) }
55+
{}
56+
57+
void ExecutionContext::Attach(std::string data, OptionsOrMediaType mediaType)
58+
{
59+
Attach(std::move(data), cucumber::messages::attachment_content_encoding::IDENTITY, std::move(mediaType));
60+
}
61+
62+
void ExecutionContext::Attach(std::istream& data, OptionsOrMediaType mediaType)
63+
{
64+
std::string buffer{ std::istreambuf_iterator<char>{ data }, std::istreambuf_iterator<char>{} };
65+
66+
buffer = base64::to_base64(buffer);
67+
68+
Attach(std::move(buffer), cucumber::messages::attachment_content_encoding::BASE64, mediaType);
69+
}
70+
71+
void ExecutionContext::Log(std::string text)
72+
{
73+
Attach(std::move(text), std::string{ LogMediaType });
74+
}
75+
76+
void ExecutionContext::Link(std::string url, std::optional<std::string> title)
77+
{
78+
Attach(std::move(url), AttachOptions{
79+
.mediaType = LinkMediaType,
80+
.fileName = std::move(title),
81+
});
82+
}
83+
84+
void ExecutionContext::Attach(std::string data, cucumber::messages::attachment_content_encoding encoding, OptionsOrMediaType mediaType)
85+
{
86+
const auto options = std::holds_alternative<std::string>(mediaType)
87+
? AttachOptions{ .mediaType = std::get<std::string>(mediaType) }
88+
: std::get<AttachOptions>(mediaType);
89+
90+
auto [test_case_started_id, test_step_id] = ReadTestStepStartedIds(stepOrHookStarted);
91+
auto [test_run_started_id, test_run_hook_started_id] = ReadTestRunHookStartedIds(stepOrHookStarted);
92+
93+
broadCaster.BroadcastEvent({
94+
.attachment = cucumber::messages::attachment{
95+
.body = std::move(data),
96+
.content_encoding = encoding,
97+
.file_name = std::move(options.fileName),
98+
.media_type = std::move(options.mediaType),
99+
.test_case_started_id = std::move(test_case_started_id),
100+
.test_step_id = std::move(test_step_id),
101+
.test_run_started_id = std::move(test_run_started_id),
102+
.test_run_hook_started_id = std::move(test_run_hook_started_id),
103+
.timestamp = support::TimestampNow(),
104+
},
105+
});
106+
}
107+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#ifndef ENGINE_EXECUTION_CONTEXT_HPP
2+
#define ENGINE_EXECUTION_CONTEXT_HPP
3+
4+
#include "cucumber/messages/attachment_content_encoding.hpp"
5+
#include "cucumber/messages/test_run_hook_started.hpp"
6+
#include "cucumber/messages/test_step_started.hpp"
7+
#include "cucumber_cpp/library/Context.hpp"
8+
#include "cucumber_cpp/library/util/Broadcaster.hpp"
9+
#include <istream>
10+
#include <optional>
11+
#include <string>
12+
#include <variant>
13+
14+
namespace cucumber_cpp::library::engine
15+
{
16+
struct AttachOptions
17+
{
18+
std::string mediaType;
19+
std::optional<std::string> fileName;
20+
};
21+
22+
using OptionsOrMediaType = std::variant<std::string, AttachOptions>;
23+
using StepOrHookStarted = std::variant<cucumber::messages::test_step_started, cucumber::messages::test_run_hook_started>;
24+
25+
struct ExecutionContext
26+
{
27+
ExecutionContext(util::Broadcaster& broadCaster, Context& context, StepOrHookStarted stepOrHookStarted);
28+
29+
protected:
30+
void Attach(std::string data, OptionsOrMediaType mediaType);
31+
void Attach(std::istream& data, OptionsOrMediaType mediaType);
32+
void Log(std::string text);
33+
void Link(std::string url, std::optional<std::string> title);
34+
35+
Context& context;
36+
37+
private:
38+
void Attach(std::string data, cucumber::messages::attachment_content_encoding encoding, OptionsOrMediaType mediaType);
39+
40+
util::Broadcaster& broadCaster;
41+
StepOrHookStarted stepOrHookStarted;
42+
};
43+
}
44+
45+
#endif

cucumber_cpp/library/engine/Step.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
#include "cucumber_cpp/library/engine/Step.hpp"
2-
#include "cucumber/messages/doc_string.hpp"
2+
#include "cucumber/messages/pickle_doc_string.hpp"
33
#include "cucumber/messages/pickle_table_row.hpp"
44
#include "cucumber_cpp/CucumberCpp.hpp"
55
#include "cucumber_cpp/library/Context.hpp"
6-
#include <functional>
6+
#include "cucumber_cpp/library/engine/ExecutionContext.hpp"
7+
#include "cucumber_cpp/library/util/Broadcaster.hpp"
78
#include <optional>
89
#include <source_location>
910
#include <span>
1011
#include <string>
1112

1213
namespace cucumber_cpp::library::engine
1314
{
14-
Step::Step(Context& context, std::optional<std::span<const cucumber::messages::pickle_table_row>> table, const std::optional<cucumber::messages::pickle_doc_string>& docString)
15-
: context{ context }
15+
Step::Step(util::Broadcaster& broadCaster, Context& context, engine::StepOrHookStarted stepOrHookStarted, std::optional<std::span<const cucumber::messages::pickle_table_row>> table, const std::optional<cucumber::messages::pickle_doc_string>& docString)
16+
: ExecutionContext{ broadCaster, context, stepOrHookStarted }
1617
, table{ table }
1718
, docString{ docString }
1819
{}

cucumber_cpp/library/engine/Step.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
#include "cucumber/messages/pickle_doc_string.hpp"
88
#include "cucumber/messages/pickle_table_row.hpp"
99
#include "cucumber_cpp/library/Context.hpp"
10+
#include "cucumber_cpp/library/engine/ExecutionContext.hpp"
11+
#include "cucumber_cpp/library/util/Broadcaster.hpp"
1012
#include <exception>
11-
#include <functional>
1213
#include <optional>
1314
#include <source_location>
1415
#include <span>
@@ -17,7 +18,7 @@
1718

1819
namespace cucumber_cpp::library::engine
1920
{
20-
struct Step
21+
struct Step : ExecutionContext
2122
{
2223
struct StepPending : std::exception
2324
{
@@ -31,7 +32,7 @@ namespace cucumber_cpp::library::engine
3132
std::source_location sourceLocation;
3233
};
3334

34-
Step(Context& context, std::optional<std::span<const cucumber::messages::pickle_table_row>> table, const std::optional<cucumber::messages::pickle_doc_string>& docString);
35+
Step(util::Broadcaster& broadCaster, Context& context, engine::StepOrHookStarted stepOrHookStarted, std::optional<std::span<const cucumber::messages::pickle_table_row>> table, const std::optional<cucumber::messages::pickle_doc_string>& docString);
3536
virtual ~Step() = default;
3637

3738
virtual void SetUp()
@@ -51,7 +52,6 @@ namespace cucumber_cpp::library::engine
5152

5253
[[noreturn]] static void Pending(const std::string& message, std::source_location current = std::source_location::current()) noexcept(false);
5354

54-
Context& context;
5555
std::optional<std::span<const cucumber::messages::pickle_table_row>> table;
5656
const std::optional<cucumber::messages::pickle_doc_string>& docString;
5757
};

cucumber_cpp/library/runtime/TestCaseRunner.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,12 @@ namespace cucumber_cpp::library::runtime
133133

134134
for (const auto& testStep : testCase.test_steps)
135135
{
136-
broadcaster.BroadcastEvent({ .test_step_started = cucumber::messages::test_step_started{
137-
.test_case_started_id = currentTestCaseStartedId,
138-
.test_step_id = testStep.id,
139-
.timestamp = support::TimestampNow(),
140-
} });
136+
auto testStepStarted = cucumber::messages::test_step_started{
137+
.test_case_started_id = currentTestCaseStartedId,
138+
.test_step_id = testStep.id,
139+
.timestamp = support::TimestampNow(),
140+
};
141+
broadcaster.BroadcastEvent({ .test_step_started = testStepStarted });
141142

142143
cucumber::messages::test_step_result testStepResult;
143144

@@ -148,7 +149,7 @@ namespace cucumber_cpp::library::runtime
148149
else
149150
{
150151
auto pickleStepIter = std::ranges::find(pickle.steps, testStep.pickle_step_id.value(), &cucumber::messages::pickle_step::id);
151-
testStepResult = RunStep(*pickleStepIter, testStep, testCaseContext);
152+
testStepResult = RunStep(*pickleStepIter, testStep, testCaseContext, testStepStarted);
152153
seenSteps = true;
153154
}
154155
testStepResults.emplace_back(testStepResult);
@@ -198,7 +199,7 @@ namespace cucumber_cpp::library::runtime
198199
return results;
199200
}
200201

201-
cucumber::messages::test_step_result TestCaseRunner::RunStep(const cucumber::messages::pickle_step& pickleStep, const cucumber::messages::test_step& testStep, Context& testCaseContext)
202+
cucumber::messages::test_step_result TestCaseRunner::RunStep(const cucumber::messages::pickle_step& pickleStep, const cucumber::messages::test_step& testStep, Context& testCaseContext, cucumber::messages::test_step_started testStepStarted)
202203
{
203204
auto stepDefinitions = (*testStep.step_definition_ids) | std::views::transform([&](const std::string& id)
204205
{
@@ -257,7 +258,7 @@ namespace cucumber_cpp::library::runtime
257258
return std::nullopt;
258259
};
259260

260-
const auto result = InvokeStep(definition.factory(testCaseContext, toOptionalTable(pickleStep), pickleStep.argument ? pickleStep.argument->doc_string : std::nullopt), parameters);
261+
const auto result = InvokeStep(definition.factory(broadcaster, testCaseContext, testStepStarted, toOptionalTable(pickleStep), pickleStep.argument ? pickleStep.argument->doc_string : std::nullopt), parameters);
261262
stepResults.push_back(result);
262263
}
263264

cucumber_cpp/library/runtime/TestCaseRunner.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "cucumber/messages/test_step.hpp"
1010
#include "cucumber/messages/test_step_result.hpp"
1111
#include "cucumber/messages/test_step_result_status.hpp"
12+
#include "cucumber/messages/test_step_started.hpp"
1213
#include "cucumber_cpp/CucumberCpp.hpp"
1314
#include "cucumber_cpp/library/Body.hpp"
1415
#include "cucumber_cpp/library/HookRegistry.hpp"
@@ -40,7 +41,7 @@ namespace cucumber_cpp::library::runtime
4041

4142
std::vector<cucumber::messages::test_step_result> RunStepHooks(const cucumber::messages::pickle_step& pickleStep, HookType hookType, Context& testCaseContext);
4243

43-
cucumber::messages::test_step_result RunStep(const cucumber::messages::pickle_step& pickleStep, const cucumber::messages::test_step& testStep, Context& testCaseContext);
44+
cucumber::messages::test_step_result RunStep(const cucumber::messages::pickle_step& pickleStep, const cucumber::messages::test_step& testStep, Context& testCaseContext, cucumber::messages::test_step_started testStepStarted);
4445

4546
cucumber::messages::test_step_result InvokeStep(std::unique_ptr<Body> body, const ExecuteArgs& args = {});
4647
cucumber::messages::test_step_result GetWorstStepResult() const;

external/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ add_subdirectory(cucumber)
77
add_subdirectory(googletest)
88
add_subdirectory(jbeder)
99
add_subdirectory(jupyter-xeus)
10+
add_subdirectory(tobiaslocker)
1011
add_subdirectory(zeux)

0 commit comments

Comments
 (0)