[libcamera-devel] [PATCH 2/2] test: Add tests for the Flags class
Kieran Bingham
kieran.bingham at ideasonboard.com
Mon Apr 26 13:51:40 CEST 2021
On 26/04/2021 09:34, Laurent Pinchart wrote:
> Hi Kieran,
>
> On Mon, Apr 26, 2021 at 09:22:05AM +0100, Kieran Bingham wrote:
>> On 25/07/2020 00:08, Laurent Pinchart wrote:
>>> Add tests that exercise the whole API of the Flags class.
>>>
>>> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
>>> ---
>>> test/flags.cpp | 204 +++++++++++++++++++++++++++++++++++++++++++++++
>>> test/meson.build | 1 +
>>> 2 files changed, 205 insertions(+)
>>> create mode 100644 test/flags.cpp
>>>
>>> diff --git a/test/flags.cpp b/test/flags.cpp
>>> new file mode 100644
>>> index 000000000000..82eca556f35e
>>> --- /dev/null
>>> +++ b/test/flags.cpp
>>> @@ -0,0 +1,204 @@
>>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>>> +/*
>>> + * Copyright (C) 2020, Google Inc.
>>> + *
>>> + * flags.cpp - Flags tests
>>> + */
>>> +
>>> +#include <iostream>
>>> +
>>> +#include <libcamera/flags.h>
>>> +
>>> +#include "test.h"
>>> +
>>> +using namespace libcamera;
>>> +using namespace std;
>>> +
>>> +class FlagsTest : public Test
>>> +{
>>> +protected:
>>> + enum class Option {
>>> + First = (1 << 0),
>>> + Second = (1 << 1),
>>> + Third = (1 << 2),
>>> + };
>>> +
>>> + using Options = Flags<Option>;
>>> +
>>> + enum class Mode {
>>> + Alpha = (1 << 0),
>>> + Beta = (1 << 2),
>>> + Gamma = (1 << 2),
>>
>> I have to wonder if this is an intentional 'fault' ?
>
> Oops. Absolutely non-intentional.
>
>> Or is there be a better way to ensure that the bit field enums are not
>> incorrectly duplicated?
>> An enum automatically assigns numbers, so it's a shame to take the
>> automatic assignment, and replace it with a manual error prone detail.
>>
>> Unfortunately I don't expect there's a way to make an enum automatically
>> <<= 1 instead of += 1
>
> It may be possible to tweak the Flags class to do this. Anyone wants to
> have fun with templates ? :-)
Not entirely fond of this but I asked on a CPP discord channel and
someone suggested it can be done with X-Macro, which seems to be some
existing macro pattern.
https://godbolt.org/z/EnEWoeGYv
I suspect perhaps that could be wrapped into a template too, which might
potentially be more friendly than the continuous line X() X() X() macro..
>>> + };
>>> +
>>> + using Modes = Flags<Mode>;
>>> +
>>> + int run() override;
>>> +};
>>> +
>>> +namespace libcamera {
>>> +
>>> +LIBCAMERA_FLAGS_ENABLE_OPERATORS(FlagsTest::Option)
>>> +
>>> +} /* namespace libcamera */
>>> +
>>> +int FlagsTest::run()
>>> +{
>>> + /* Commented-out constructs are expected not compile. */
>>> +
>>> + /* Flags<int> f; */
>>> +
>>> + /*
>>> + * Unary operators with enum argument.
>>> + */
>>> +
>>> + Options options;
>>> +
>>> + if (options) {
>>> + cerr << "Default-constructed Flags<> is not zero" << endl;
>>> + return TestFail;
>>> + }
>>> +
>>> + options |= Option::First;
>>> +
>>> + if (!options || options != Option::First) {
>>> + cerr << "Unary bitwise OR with enum failed" << endl;
>>> + return TestFail;
>>> + }
>>> +
>>> + /* options &= Mode::Alpha; */
>>> + /* options |= Mode::Beta; */
>>> + /* options ^= Mode::Gamma; */
>>> +
>>> + options &= ~Option::First;
>>> +
>>> + if (options) {
>>> + cerr << "Unary bitwise AND with enum failed" << endl;
>>> + return TestFail;
>>> + }
>>> +
>>> + options ^= Option::Second;
>>> +
>>> + if (options != Option::Second) {
>>> + cerr << "Unary bitwise XOR with enum failed" << endl;
>>> + return TestFail;
>>> + }
>>> +
>>> + options = Options();
>>> +
>>> + /*
>>> + * Unary operators with Flags argument.
>>> + */
>>> +
>>> + options |= Options(Option::First);
>>> +
>>> + if (options != Option::First) {
>>> + cerr << "Unary bitwise OR with Flags<> failed" << endl;
>>> + return TestFail;
>>> + }
>>> +
>>> + /* options &= Options(Mode::Alpha); */
>>> + /* options |= Options(Mode::Beta); */
>>> + /* options ^= Options(Mode::Gamma); */
>>> +
>>> + options &= ~Options(Option::First);
>>> +
>>> + if (options) {
>>> + cerr << "Unary bitwise AND with Flags<> failed" << endl;
>>> + return TestFail;
>>> + }
>>> +
>>> + options ^= Options(Option::Second);
>>> +
>>> + if (options != Option::Second) {
>>> + cerr << "Unary bitwise XOR with Flags<> failed" << endl;
>>> + return TestFail;
>>> + }
>>> +
>>> + options = Options();
>>> +
>>> + /*
>>> + * Binary operators with enum argument.
>>> + */
>>> +
>>> + options = options | Option::First;
>>> +
>>> + if (!(options & Option::First)) {
>>> + cerr << "Binary bitwise OR with enum failed" << endl;
>>> + return TestFail;
>>> + }
>>> +
>>> + /* options = options & Mode::Alpha; */
>>> + /* options = options | Mode::Beta; */
>>> + /* options = options ^ Mode::Gamma; */
>>> +
>>> + options = options & ~Option::First;
>>> +
>>> + if (options != (Option::First & Option::Second)) {
>>> + cerr << "Binary bitwise AND with enum failed" << endl;
>>> + return TestFail;
>>> + }
>>> +
>>> + options = options ^ (Option::First ^ Option::Second);
>>> +
>>> + if (options != (Option::First | Option::Second)) {
>>> + cerr << "Binary bitwise XOR with enum failed" << endl;
>>> + return TestFail;
>>> + }
>>> +
>>> + options = Options();
>>> +
>>> + /*
>>> + * Binary operators with Flags argument.
>>> + */
>>> +
>>> + options |= Options(Option::First);
>>> +
>>> + if (!(options & Option::First)) {
>>> + cerr << "Binary bitwise OR with Flags<> failed" << endl;
>>> + return TestFail;
>>> + }
>>> +
>>> + /* options = options & Options(Mode::Alpha); */
>>> + /* options = options | Options(Mode::Beta); */
>>> + /* options = options ^ Options(Mode::Gamma); */
>>> +
>>> + options = options & ~Options(Option::First);
>>> +
>>> + if (options) {
>>> + cerr << "Binary bitwise AND with Flags<> failed" << endl;
>>> + return TestFail;
>>> + }
>>> +
>>> + options = options ^ Options(Option::Second);
>>> +
>>> + if (options != Option::Second) {
>>> + cerr << "Binary bitwise XOR with Flags<> failed" << endl;
>>> + return TestFail;
>>> + }
>>> +
>>> + options = Options();
>>> +
>>> + /*
>>> + * Conversion operators.
>>> + */
>>> + options |= Option::First | Option::Second | Option::Third;
>>> + if (static_cast<Options::Type>(options) != 7) {
>>> + cerr << "Cast to underlying type failed" << endl;
>>> + return TestFail;
>>> + }
>>> +
>>> + /*
>>> + * Conversion of the result of ninary operators on the underlying enum.
>>> + */
>>> +
>>> + /* unsigned int val1 = Option::First; */
>>> + /* unsigned int val2 = ~Option::First; */
>>> + /* unsigned int val3 = Option::First | Option::Second; */
>>> + /* Option val4 = ~Option::First; */
>>> + /* Option val5 = Option::First | Option::Second; */
>>> +
>>> + return TestPass;
>>> +}
>>> +
>>> +TEST_REGISTER(FlagsTest)
>>> diff --git a/test/meson.build b/test/meson.build
>>> index f41d6e740e6a..81b20521e8cb 100644
>>> --- a/test/meson.build
>>> +++ b/test/meson.build
>>> @@ -31,6 +31,7 @@ internal_tests = [
>>> ['event-thread', 'event-thread.cpp'],
>>> ['file', 'file.cpp'],
>>> ['file-descriptor', 'file-descriptor.cpp'],
>>> + ['flags', 'flags.cpp'],
>>> ['hotplug-cameras', 'hotplug-cameras.cpp'],
>>> ['message', 'message.cpp'],
>>> ['object', 'object.cpp'],
>
--
Regards
--
Kieran
More information about the libcamera-devel
mailing list