diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 85115b5..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "spec"] - path = spec - url = https://github.com/open-feature/spec.git diff --git a/BUILD b/BUILD index 6066694..ffd0fb0 100644 --- a/BUILD +++ b/BUILD @@ -1,8 +1 @@ -load("@rules_gherkin//gherkin:defs.bzl", "gherkin_library") - package(default_visibility = ["//visibility:public"]) - -gherkin_library( - name = "openfeature_gherkin_spec_features", - srcs = glob(["spec/specification/assets/gherkin/evaluation.feature"]), -) \ No newline at end of file diff --git a/Gemfile b/Gemfile deleted file mode 100644 index c0128f5..0000000 --- a/Gemfile +++ /dev/null @@ -1,3 +0,0 @@ -source 'https://rubygems.org' -gem 'cucumber', '~> 10.2.0' -gem 'cucumber-wire', '~> 8.0.0' \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index a0f4b35..0000000 --- a/Gemfile.lock +++ /dev/null @@ -1,56 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - base64 (0.3.0) - bigdecimal (4.0.1) - bigdecimal (4.0.1-java) - builder (3.3.0) - cucumber (10.2.0) - base64 (~> 0.2) - builder (~> 3.2) - cucumber-ci-environment (> 9, < 12) - cucumber-core (> 15, < 17) - cucumber-cucumber-expressions (> 17, < 20) - cucumber-html-formatter (> 21, < 23) - diff-lcs (~> 1.5) - logger (~> 1.6) - mini_mime (~> 1.1) - multi_test (~> 1.1) - sys-uname (~> 1.3) - cucumber-ci-environment (11.0.0) - cucumber-core (15.4.0) - cucumber-gherkin (> 27, < 40) - cucumber-messages (> 26, < 33) - cucumber-tag-expressions (> 5, < 9) - cucumber-cucumber-expressions (19.0.0) - bigdecimal - cucumber-gherkin (38.0.0) - cucumber-messages (>= 31, < 33) - cucumber-html-formatter (22.3.0) - cucumber-messages (> 23, < 33) - cucumber-messages (32.0.1) - cucumber-tag-expressions (8.1.0) - cucumber-wire (8.0.0) - cucumber-core (> 11, < 16) - cucumber-cucumber-expressions (> 14, < 20) - diff-lcs (1.6.2) - ffi (1.17.3-java) - ffi (1.17.3-x86_64-linux-gnu) - logger (1.7.0) - memoist3 (1.0.0) - mini_mime (1.1.5) - multi_test (1.1.0) - sys-uname (1.5.0) - ffi (~> 1.1) - memoist3 (~> 1.0.0) - -PLATFORMS - universal-java-11 - x86_64-linux - -DEPENDENCIES - cucumber (~> 10.2.0) - cucumber-wire (~> 8.0.0) - -BUNDLED WITH - 2.4.19 diff --git a/MODULE.bazel b/MODULE.bazel index 45d26b2..67bbd96 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -3,34 +3,41 @@ module(name = "openfeature_cpp_sdk") bazel_dep(name = "googletest", version = "1.17.0.bcr.2") bazel_dep(name = "abseil-cpp", version = "20250814.2") bazel_dep(name = "rules_cc", version = "0.2.17") -bazel_dep(name = "cucumber-cpp", version = "0.8.0.bcr.1") -bazel_dep(name = "rules_gherkin", version = "0.2.0") -bazel_dep(name = "rules_ruby", version = "0.23.1") - -# Hermetic Ruby Toolchain Configuration -ruby = use_extension("@rules_ruby//ruby:extensions.bzl", "ruby") -ruby.toolchain( - name = "ruby", - version = "3.2.2", # JRuby or standard MRI version suitable for execution -) - -# Cucumber Gem provisioning via Bundler integration -ruby.bundle_fetch( - name = "cucumber", - gemfile = "//:Gemfile", - gemfile_lock = "//:Gemfile.lock", -) -use_repo(ruby, "cucumber", "ruby", "ruby_toolchains") -register_toolchains("@ruby_toolchains//:all") - -# Hedron's Compile Commands Extractor for Bazel -# https://github.com/hedronvision/bazel-compile-commands-extractor +#Hedron's Compile Commands Extractor for Bazel +#https: // github.com/hedronvision/bazel-compile-commands-extractor bazel_dep(name = "hedron_compile_commands", dev_dependency = True) git_override( module_name = "hedron_compile_commands", remote = "https://github.com/hedronvision/bazel-compile-commands-extractor.git", - # Not official but well established fork with a fix to header only libraries - # https://github.com/hedronvision/bazel-compile-commands-extractor/pull/219 +#Not official but well established fork with a fix to header only libraries +#https: // github.com/hedronvision/bazel-compile-commands-extractor/pull/219 commit = "02d15621b528efd877f5d5657c4b738523a0eb17", ) + +git_repository = use_repo_rule("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +#Fetch cwt - cucumber directly from GitHub +git_repository( + name = "cwt_cucumber", + build_file = "//test/e2e:cwt_cucumber.BUILD", + remote = "https://github.com/ThoSe1990/cwt-cucumber.git", + tag = "2.8", +) + +#Fetch OpenFeature spec for Gherkin scenarios +git_repository( + name = "openfeature_spec", + remote = "https://github.com/open-feature/spec.git", + branch = "main", + build_file_content = """ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "gherkin_features", +#TODO : Once the SDK is finished, \ + the source should be changed to "specification/assets/gherkin/*.feature" + srcs = glob(["specification/assets/gherkin/evaluation.feature"]), +) +""", +) \ No newline at end of file diff --git a/spec b/spec deleted file mode 160000 index eefdf43..0000000 --- a/spec +++ /dev/null @@ -1 +0,0 @@ -Subproject commit eefdf439c5a5b69ccde036c3c6959a4a6c17e08c diff --git a/test/e2e/BUILD b/test/e2e/BUILD index 9a3ef3b..64b4272 100644 --- a/test/e2e/BUILD +++ b/test/e2e/BUILD @@ -1,10 +1,11 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -load("@rules_gherkin//gherkin:defs.bzl", "gherkin_test") package( default_visibility = ["//visibility:public"], ) +exports_files(["cwt-cucumber.BUILD"]) + cc_library( name = "context_storing_provider", srcs = [ @@ -22,7 +23,6 @@ cc_library( "//openfeature:reason", "//openfeature:value", "//openfeature:resolution_details", - "@cucumber-cpp//:cucumber-cpp", "@googletest//:gtest", ], ) @@ -51,10 +51,12 @@ cc_library( ], ) -gherkin_test( +cc_test( name = "openfeature_gherkin_e2e_tests", - steps = "//test/e2e/steps:gherkin_step_definitions", + data = ["@openfeature_spec//:gherkin_features"], + args =["$(locations @openfeature_spec//:gherkin_features)"], deps = [ - "//:openfeature_gherkin_spec_features", + "//test/e2e/steps:gherkin_step_definitions", + "@cwt_cucumber//:cwt-cucumber", ], ) diff --git a/test/e2e/context_storing_provider.cpp b/test/e2e/context_storing_provider.cpp index c07e110..f9e7496 100644 --- a/test/e2e/context_storing_provider.cpp +++ b/test/e2e/context_storing_provider.cpp @@ -2,15 +2,12 @@ #include -#include #include #include "openfeature/flag_metadata.h" #include "openfeature/reason.h" #include "openfeature/value.h" -using cucumber::ScenarioScope; - namespace openfeature_e2e { openfeature::Metadata ContextStoringProvider::GetMetadata() const { diff --git a/test/e2e/cwt_cucumber.BUILD b/test/e2e/cwt_cucumber.BUILD new file mode 100644 index 0000000..87c497b --- /dev/null +++ b/test/e2e/cwt_cucumber.BUILD @@ -0,0 +1,31 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +# Generate the version file from the template by extracting the version from CMakeLists.txt +genrule( + name = "generate_version_file", + srcs = [ + "CMakeLists.txt", + "src/version.template", + ], + outs = ["src/version.hpp"], + cmd = """ + VERSION=$$(grep 'project(cwt-cucumber VERSION' $(location CMakeLists.txt) | sed 's/.*VERSION \\([0-9.]*\\).*/\\1/'); + sed "s/@PROJECT_VERSION@/$$VERSION/g" $(location src/version.template) > $@ + """, +) + +cc_library( + name = "cwt-cucumber", + srcs = glob( + ["src/**/*.cpp"], + exclude = ["src/main.cpp"], + ), + hdrs = glob([ + "src/**/*.hpp", + ]) + [ + "src/version.hpp", + ], + copts = ["-std=c++20"], + strip_include_prefix = "src", + visibility = ["//visibility:public"], +) diff --git a/test/e2e/steps/BUILD b/test/e2e/steps/BUILD index b8a6204..e624154 100644 --- a/test/e2e/steps/BUILD +++ b/test/e2e/steps/BUILD @@ -1,10 +1,11 @@ -load("@rules_gherkin//gherkin:defs.bzl", "cc_gherkin_steps") +load("@rules_cc//cc:defs.bzl", "cc_library") package(default_visibility = ["//visibility:public"]) -cc_gherkin_steps( +cc_library( name = "gherkin_step_definitions", srcs = ["minimal_steps.cpp"], + copts = ["-std=c++20"], deps = [ "//openfeature:evaluation_context", "//openfeature:openfeature_api", @@ -13,7 +14,7 @@ cc_gherkin_steps( "//test/e2e:context_storing_provider", "//test/e2e:state", "//test:mock_feature_provider", - "@cucumber-cpp//:cucumber-cpp", + "@cwt_cucumber//:cwt-cucumber", "@googletest//:gtest", ], visibility = ["//test/e2e:__subpackages__"], diff --git a/test/e2e/steps/minimal_steps.cpp b/test/e2e/steps/minimal_steps.cpp index bcdf998..8b4f2b8 100644 --- a/test/e2e/steps/minimal_steps.cpp +++ b/test/e2e/steps/minimal_steps.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include @@ -18,10 +18,14 @@ #include "test/e2e/state.h" #include "test/mocks/mock_feature_provider.h" -using ::cucumber::ScenarioScope; using ::testing::_; using ::testing::Return; +constexpr int64_t kDefaultIntegerFlagValue = 10; +constexpr double kDefaultFloatFlagValue = 0.5; +constexpr int64_t kImagesPerPageValue = 100; +constexpr auto kProviderInitDelay = std::chrono::milliseconds(200); + // Helper to create simple static flags for the InMemoryProvider. template openfeature::Flag CreateStaticFlag(T value) { @@ -38,14 +42,14 @@ std::shared_ptr CreateStableProvider() { // Set up the static flags expected by the basic evaluation tests. flags["boolean-flag"] = CreateStaticFlag(true); flags["string-flag"] = CreateStaticFlag("hi"); - flags["integer-flag"] = CreateStaticFlag(10); - flags["float-flag"] = CreateStaticFlag(0.5); + flags["integer-flag"] = CreateStaticFlag(kDefaultIntegerFlagValue); + flags["float-flag"] = CreateStaticFlag(kDefaultFloatFlagValue); // Object flag setup. std::map obj_map; obj_map["showImages"] = openfeature::Value(true); obj_map["title"] = openfeature::Value("Check out these pics!"); - obj_map["imagesPerPage"] = openfeature::Value(100); + obj_map["imagesPerPage"] = openfeature::Value(kImagesPerPageValue); flags["object-flag"] = CreateStaticFlag(openfeature::Value(obj_map)); @@ -86,38 +90,37 @@ std::shared_ptr CreateMockNotReadyProvider() { EXPECT_CALL(*mock, Shutdown()).WillRepeatedly(Return(absl::OkStatus())); EXPECT_CALL(*mock, Init(_)) .WillOnce(testing::Invoke([](const openfeature::EvaluationContext&) { - std::this_thread::sleep_for(std::chrono::milliseconds(200)); + std::this_thread::sleep_for(kProviderInitDelay); return absl::OkStatus(); })); return mock; } -GIVEN("^a (.*) provider$") { - REGEX_PARAM(std::string, status_type); - ScenarioScope state; +GIVEN(provider_setup, "a {word} provider") { + std::string status_type = CUKE_ARG(1); + auto& state = cuke::context(); if (status_type == "stable" || status_type == "ready") { - state->provider = CreateStableProvider(); + state.provider = CreateStableProvider(); openfeature::OpenFeatureAPI::GetInstance().SetProviderAndWait( - state->provider); + state.provider); } else if (status_type == "error") { - state->provider = CreateMockErrorProvider(); + state.provider = CreateMockErrorProvider(); openfeature::OpenFeatureAPI::GetInstance().SetProviderAndWait( - state->provider); + state.provider); } else if (status_type == "not ready") { - state->provider = CreateMockNotReadyProvider(); - openfeature::OpenFeatureAPI::GetInstance().SetProvider(state->provider); + state.provider = CreateMockNotReadyProvider(); + openfeature::OpenFeatureAPI::GetInstance().SetProvider(state.provider); } - state->client = openfeature::OpenFeatureAPI::GetInstance().GetClient(); + state.client = openfeature::OpenFeatureAPI::GetInstance().GetClient(); } -THEN("^the provider status should be \"([^\"]*)\"$") { - REGEX_PARAM(std::string, expected_status_str); - ScenarioScope state; +THEN(check_provider_status, "the provider status should be {string}") { + std::string expected_status_str = CUKE_ARG(1); + auto& state = cuke::context(); - openfeature::ProviderStatus actual_status = - state->client->GetProviderStatus(); + openfeature::ProviderStatus actual_status = state.client->GetProviderStatus(); openfeature::ProviderStatus expected_status = openfeature::ProviderStatus::kReady; @@ -136,167 +139,184 @@ THEN("^the provider status should be \"([^\"]*)\"$") { EXPECT_EQ(actual_status, expected_status); } -WHEN( - "^a boolean flag with key \"([^\"]*)\" is evaluated with default value " - "\"([^\"]*)\"$") { - REGEX_PARAM(std::string, key); - REGEX_PARAM(std::string, default_val_str); - ScenarioScope state; +WHEN(eval_boolean_flag, + "a boolean flag with key {string} is evaluated with default value " + "{string}") { + std::string key = CUKE_ARG(1); + std::string default_val_str = CUKE_ARG(2); + auto& state = cuke::context(); bool default_val = (default_val_str == "true"); - state->last_evaluation_value = - openfeature::Value(state->client->GetBooleanValue(key, default_val)); + state.last_evaluation_value = + openfeature::Value(state.client->GetBooleanValue(key, default_val)); } -THEN("^the resolved boolean value should be \"([^\"]*)\"$") { - REGEX_PARAM(std::string, expected_str); - ScenarioScope state; +THEN(check_resolved_boolean, "the resolved boolean value should be {string}") { + std::string expected_str = CUKE_ARG(1); + auto& state = cuke::context(); + bool expected = (expected_str == "true"); - EXPECT_EQ(state->last_evaluation_value.AsBool().value(), expected); + EXPECT_EQ(state.last_evaluation_value.AsBool().value(), expected); } -WHEN( - "^a string flag with key \"([^\"]*)\" is evaluated with default value " - "\"([^\"]*)\"$") { - REGEX_PARAM(std::string, key); - REGEX_PARAM(std::string, default_val); - ScenarioScope state; - - state->last_evaluation_value = - openfeature::Value(state->client->GetStringValue(key, default_val)); +WHEN(eval_string_flag, + "a string flag with key {string} is evaluated with default value " + "{string}") { + std::string key = CUKE_ARG(1); + std::string default_val = CUKE_ARG(2); + auto& state = cuke::context(); + + state.last_evaluation_value = + openfeature::Value(state.client->GetStringValue(key, default_val)); } -THEN("^the resolved string value should be \"([^\"]*)\"$") { - REGEX_PARAM(std::string, expected); - ScenarioScope state; - EXPECT_EQ(state->last_evaluation_value.AsString().value(), expected); +THEN(check_resolved_string, "the resolved string value should be {string}") { + std::string expected = CUKE_ARG(1); + auto& state = cuke::context(); + EXPECT_EQ(state.last_evaluation_value.AsString().value(), expected); } WHEN( - "^an integer flag with key \"([^\"]*)\" is evaluated with default value " - "(\\d+)$") { - REGEX_PARAM(std::string, key); - REGEX_PARAM(int64_t, default_val); - ScenarioScope state; - - state->last_evaluation_value = - openfeature::Value(state->client->GetIntegerValue(key, default_val)); + eval_integer_flag, + "an integer flag with key {string} is evaluated with default value {int}") { + std::string key = CUKE_ARG(1); + int64_t default_val = CUKE_ARG(2); + auto& state = cuke::context(); + + state.last_evaluation_value = + openfeature::Value(state.client->GetIntegerValue(key, default_val)); } -THEN("^the resolved integer value should be (\\d+)$") { - REGEX_PARAM(int64_t, expected); - ScenarioScope state; - EXPECT_EQ(state->last_evaluation_value.AsInt().value(), expected); +THEN(check_resolved_integer, "the resolved integer value should be {int}") { + int64_t expected = CUKE_ARG(1); + auto& state = cuke::context(); + EXPECT_EQ(state.last_evaluation_value.AsInt().value(), expected); } WHEN( - "^a float flag with key \"([^\"]*)\" is evaluated with default value " - "([\\d\\.]+)$") { - REGEX_PARAM(std::string, key); - REGEX_PARAM(double, default_val); - ScenarioScope state; - - state->last_evaluation_value = - openfeature::Value(state->client->GetDoubleValue(key, default_val)); + eval_float_flag, + "a float flag with key {string} is evaluated with default value {double}") { + std::string key = CUKE_ARG(1); + double default_val = CUKE_ARG(2); + auto& state = cuke::context(); + + state.last_evaluation_value = + openfeature::Value(state.client->GetDoubleValue(key, default_val)); } -THEN("^the resolved float value should be ([\\d\\.]+)$") { - REGEX_PARAM(double, expected); - ScenarioScope state; - EXPECT_DOUBLE_EQ(state->last_evaluation_value.AsDouble().value(), expected); +THEN(check_resolved_float, "the resolved float value should be {double}") { + double expected = CUKE_ARG(1); + auto& state = cuke::context(); + EXPECT_DOUBLE_EQ(state.last_evaluation_value.AsDouble().value(), expected); } WHEN( - "^an object flag with key \"([^\"]*)\" is evaluated with a null default " - "value$") { - REGEX_PARAM(std::string, key); - ScenarioScope state; + eval_object_flag_null, + "an object flag with key {string} is evaluated with a null default value") { + std::string key = CUKE_ARG(1); + auto& state = cuke::context(); - state->last_evaluation_value = - state->client->GetObjectValue(key, openfeature::Value()); + state.last_evaluation_value = + state.client->GetObjectValue(key, openfeature::Value()); } -THEN( - "^the resolved object value should be contain fields \"([^\"]*)\", " - "\"([^\"]*)\", and \"([^\"]*)\", with values \"([^\"]*)\", \"([^\"]*)\" " - "and (\\d+), respectively$") { - REGEX_PARAM(std::string, f1); - REGEX_PARAM(std::string, f2); - REGEX_PARAM(std::string, f3); - REGEX_PARAM(std::string, v1_str); - REGEX_PARAM(std::string, v2); - REGEX_PARAM(int64_t, v3); - ScenarioScope state; +THEN(check_resolved_object, + "the resolved object value should be contain fields {string}, {string}, " + "and {string}, with values {string}, {string} and {int}, respectively") { + std::string bool_field = CUKE_ARG(1); + std::string string_field = CUKE_ARG(2); + std::string int_field = CUKE_ARG(3); + std::string bool_value = CUKE_ARG(4); + std::string string_value = CUKE_ARG(5); + int64_t int_value = CUKE_ARG(6); + auto& state = cuke::context(); const std::map* structure = - state->last_evaluation_value.AsStructure(); + state.last_evaluation_value.AsStructure(); ASSERT_NE(structure, nullptr); - EXPECT_EQ(structure->at(f1).AsBool().value(), (v1_str == "true")); - EXPECT_EQ(structure->at(f2).AsString().value(), v2); - EXPECT_EQ(structure->at(f3).AsInt().value(), v3); + EXPECT_EQ(structure->at(bool_field).AsBool().value(), (bool_value == "true")); + EXPECT_EQ(structure->at(string_field).AsString().value(), string_value); + EXPECT_EQ(structure->at(int_field).AsInt().value(), int_value); } -WHEN( - "^context contains keys \"([^\"]*)\", \"([^\"]*)\", \"([^\"]*)\", " - "\"([^\"]*)\" with values \"([^\"]*)\", \"([^\"]*)\", (\\d+), " - "\"([^\"]*)\"$") { - REGEX_PARAM(std::string, k1); - REGEX_PARAM(std::string, k2); - REGEX_PARAM(std::string, k3); - REGEX_PARAM(std::string, k4); - REGEX_PARAM(std::string, v1); - REGEX_PARAM(std::string, v2); - REGEX_PARAM(int64_t, v3); - REGEX_PARAM(std::string, v4); - ScenarioScope state; +WHEN(setup_context, + "context contains keys {string}, {string}, {string}, {string} with values " + "{string}, {string}, {int}, {string}") { + std::string field1 = CUKE_ARG(1); + std::string field2 = CUKE_ARG(2); + std::string field3 = CUKE_ARG(3); + std::string field4 = CUKE_ARG(4); + std::string value1 = CUKE_ARG(5); + std::string value2 = CUKE_ARG(6); + int64_t value3 = CUKE_ARG(7); + std::string value4 = CUKE_ARG(8); + auto& state = cuke::context(); openfeature::EvaluationContext ctx = openfeature::EvaluationContext::Builder() - .WithAttribute(k1, v1) - .WithAttribute(k2, v2) - .WithAttribute(k3, v3) - .WithAttribute(k4, v4) + .WithAttribute(field1, value1) + .WithAttribute(field2, value2) + .WithAttribute(field3, value3) + .WithAttribute(field4, value4) .build(); - state->context = std::make_unique(ctx); + state.context = std::make_unique(ctx); } -WHEN( - "^a flag with key \"([^\"]*)\" is evaluated with default value " - "\"([^\"]*)\"$") { - REGEX_PARAM(std::string, key); - REGEX_PARAM(std::string, default_val); - ScenarioScope state; - - // Evaluate using the context built in the previous step. - if (state->context) { - state->last_evaluation_value = openfeature::Value( - state->client->GetStringValue(key, default_val, *state->context)); +WHEN(eval_flag_with_context, + "a flag with key {string} is evaluated with default value {string}") { + std::string key = CUKE_ARG(1); + std::string default_val = CUKE_ARG(2); + auto& state = cuke::context(); + + if (state.context) { + state.last_evaluation_value = openfeature::Value( + state.client->GetStringValue(key, default_val, *state.context)); } else { - state->last_evaluation_value = - openfeature::Value(state->client->GetStringValue(key, default_val)); + state.last_evaluation_value = + openfeature::Value(state.client->GetStringValue(key, default_val)); } } -THEN("^the resolved string response should be \"([^\"]*)\"$") { - REGEX_PARAM(std::string, expected); - ScenarioScope state; +THEN(check_resolved_string_response, + "the resolved string response should be {string}") { + std::string expected = CUKE_ARG(1); + auto& state = cuke::context(); - EXPECT_EQ(state->last_evaluation_value.AsString().value(), expected); + EXPECT_EQ(state.last_evaluation_value.AsString().value(), expected); } -THEN("^the resolved flag value is \"([^\"]*)\" when the context is empty$") { - REGEX_PARAM(std::string, expected); - ScenarioScope state; +THEN(check_resolved_flag_empty_ctx, + "the resolved flag value is {string} when the context is empty") { + std::string expected = CUKE_ARG(1); + auto& state = cuke::context(); - // Evaluate context-aware flag with an empty context. openfeature::EvaluationContext empty_ctx = openfeature::EvaluationContext::Builder().build(); std::string actual = - state->client->GetStringValue("context-aware", "EXTERNAL", empty_ctx); + state.client->GetStringValue("context-aware", "EXTERNAL", empty_ctx); EXPECT_EQ(actual, expected); } +// This function helps the test not to fail if we have an "UNDEFINED" scenario. +// It should be deleted when we are able to write steps for all scenarios. +int main(int argc, char* argv[]) { + GTEST_FLAG_SET(throw_on_failure, true); + ::testing::InitGoogleMock(&argc, argv); + + cuke::cwt_cucumber cucumber(argc, const_cast(argv)); + + cucumber.run_tests(); + + cucumber.print_results(); + + if (::testing::UnitTest::GetInstance()->failed_test_count() > 0) { + return 1; + } + + return 0; +} + // TODO: Enable more Gherkin scenarios as the SDK functionality expands, e.g. // around event hooks, detailed evaluation, etc. \ No newline at end of file