-
Notifications
You must be signed in to change notification settings - Fork 224
Create a guide for authoring in C++ #208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
@kazk could you share some insight on how solutions in C++ are built? What gets concatenated with what, what exactly is in the template (some includes? |
From codewars/runner#35 (comment) #include <igloo/igloo_alt.h>
#include <igloo/CodewarsTestListener.h>
using namespace igloo;
// #include "preloaded.h" if preloaded
// [solution]
// [tests]
int main(int, const char *[]) {
NullTestResultsOutput output;
TestRunner runner(output);
CodewarsTestListener listener;
runner.AddListener(&listener);
runner.Run();
} |
Would it still work if it looked like this: // #include "preloaded.h" if preloaded
// [solution]
#include <igloo/igloo_alt.h>
using namespace igloo;
// [tests]
#include <igloo/CodewarsTestListener.h>
int main(int, const char *[]) {
NullTestResultsOutput output;
TestRunner runner(output);
CodewarsTestListener listener;
runner.AddListener(&listener);
runner.Run();
} Not that I am proposing such change at the moment, I am just trying to figure out dependencies between snippets and what can potentially pollute what etc. |
@hobovsky asked me to share my thoughts about the proper usage of the
Some examples from me (which I actually saw on CW) // The tested function
int f(int a, int b = 0) {
return a + b;
} Describe(Bad) {
It(c_style_rand) {
srand(time(NULL));
for(int i = 0; i < 100; ++i) {
const int n = rand() % (100 - 1) + 1; // Please, let it go
Assert::That(f(n), Equals(n));
}
}
}; Describe(Bad) {
private:
int rand1_100() {
std::mt19937 engine{ std::random_device{}() };
return std::uniform_int_distribution<int>{ 1, 100 }(engine);
}
public:
It(create_pnrg_multiple_times) {
for(int i = 0; i < 100; ++i) {
const int n = rand1_100(); // PRNG is recreated 100 times.
Assert::That(f(n), Equals(n));
}
}
}; Describe(Bad) {
private:
std::mt19937 engine{ std::random_device{}() };
int rand(const int a, const int b) {
return std::uniform_int_distribution<int>{ a, b }(engine);
}
public:
It(create_distribution_multiple_times) {
for(int i = 0; i < 100; ++i) {
const int n = rand(1, 100); // Distribution range doesn't really change between cases but is recreated 100 times
Assert::That(f(n), Equals(n));
}
}
}; Describe(Bad) {
private:
std::random_device engine; // Shorter to type, but not reliable
std::uniform_int_distribution<int> dist{ 1, 100 };
public:
It(random_device_as_main_rng) {
for(int i = 0; i < 100; ++i) {
const int n = dist(engine);
Assert::That(f(n), Equals(n));
}
}
}; Describe(Bad) {
private:
std::mt19937 engine{ time(NULL) }; // It's a bad practice
std::uniform_int_distribution<int> dist{ 1, 100 };
public:
It(time_as_seed) {
for(int i = 0; i < 100; ++i) {
const int n = dist(engine);
Assert::That(f(n), Equals(n));
}
}
}; Describe(Bad) {
private:
std::mt19937 engine{ chrono::system_clock::now().time_since_epoch().count() }; // As bad as previous, but harder to read
std::uniform_int_distribution<int> dist{ 1, 100 };
public:
It(time_as_seed) {
for(int i = 0; i < 100; ++i) {
const int n = dist(engine);
Assert::That(f(n), Equals(n));
}
}
}; Describe(Bad) {
private:
std::mt19937 engine{ std::random_device{}() };
public:
It(random_shuffle) {
std::array<int, 100> arr;
std::generate_n(arr.begin(), 100, [n = 0]() mutable { return ++n; });
// Inventing the wheel.
for(int i = 0; i < 100; ++i) {
std::uniform_int_distribution<int> dist{ i, 99 };
std::swap(arr[i], arr[dist(engine)]);
}
for(int i = 0; i < 100; ++i) {
const int n = arr[i];
Assert::That(f(n), Equals(n));
}
}
}; Describe(Bad) {
private:
std::mt19937 engine{ std::random_device{}() };
public:
It(pick_elements_with_shuffle) {
std::array<int, 100> arr;
std::generate_n(arr.begin(), 100, [n = 0]() mutable { return ++n; });
for(int i = 0; i < 100; ++i) {
std::shuffle(arr.begin(), arr.end()); // Performs a ton of job for just getting two numbers
Assert::That(f(arr[0], arr[1]), Equals(arr[0] + arr[1]));
}
}
}; And how it (in my opinion) should be Describe(Good) {
private:
std::mt19937 engine{ std::random_device{}() };
std::uniform_int_distribution<int> dist{ 1, 100 };
public:
It(random_numbers) {
for(int i = 0; i < 100; ++i) {
const int n = dist(engine);
Assert::That(f(n), Equals(n));
}
}
It(random_sequence) {
std::array<int, 100> arr;
std::generate_n(arr.begin(), 100, [n = 0]() mutable { return ++n; });
std::shuffle(arr.begin(), arr.end(), engine);
for(int i = 0; i < 100; ++i) {
const int n = arr[i];
Assert::That(f(n), Equals(n));
}
}
It(random_pick) {
std::array<int, 100> arr;
std::generate_n(arr.begin(), 100, [n = 0]() mutable { return ++n; });
int n[2];
for(int i = 0; i < 100; ++i) {
std::sample(arr.cbegin(), arr.cend(), n, 2, engine);
Assert::That(f(n[0], n[1]), Equals(n[0] + n[1]));
}
}
}; Also, not part of the main thing, but maybe a bit of useful advice. To avoid writing Describe(WhoKnows) {
private:
std::mt19937 engine{ std::random_device{}() };
std::function<int()> rand_number = std::bind(std::uniform_int_distribution<int>{ 1, 100 }, engine);
std::function<size_t()> rand_length = std::bind(std::uniform_int_distribution<size_t>{ 20, 100 }, engine);
std::function<double()> rand_coefficient = std::bind(std::uniform_real_distribution<double>{ -1, 1 }, engine);
std::function<char()> rand_letter = std::bind(std::uniform_int_distribution<char>{ 'a', 'z' }, engine);
std::function<bool()> rand_bool = std::bind(std::uniform_int_distribution<char>{ 0, 1 }, engine);
// and etc.
}; After you can call them directly by That's it. I hope, I didn't miss anything. |
Random tests don't need ideal distributions, thread safety or anything like that, so the recommendations above are more like what examples in the guide probably should use, but I don't see anything bad if someone likes to use |
I am not bothered at all by quality of random data generated with When reviewing, I would be perfectly fine with correctly used |
From the standpoint of a less-honest user |
Create an article similar to https://docs.codewars.com/languages/python/authoring/ but for C++.
Points needing particular attention:
std::vector
The text was updated successfully, but these errors were encountered: