Skip to content

Commit

Permalink
Merge pull request #1236 from spark/fix/publish_flags
Browse files Browse the repository at this point in the history
Particle.publish() flags fixes
  • Loading branch information
technobly committed Mar 14, 2017
2 parents cb8a39c + 25e4972 commit 7bf2aa8
Show file tree
Hide file tree
Showing 6 changed files with 491 additions and 71 deletions.
258 changes: 258 additions & 0 deletions user/tests/unit/flags.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
#include "spark_wiring_flags.h"

#include "tools/catch.h"

#include <limits>

namespace {

using namespace particle;

enum FlagUint {
FLAG_1 = 0x01,
FLAG_2 = 0x02,
FLAG_NONE = 0x00,
FLAG_ALL = std::numeric_limits<unsigned>::max()
};

enum class FlagUint8: uint8_t {
FLAG_1 = 0x01,
FLAG_2 = 0x02,
FLAG_NONE = 0x00,
FLAG_ALL = 0xff
};

enum class FlagUint64: uint64_t {
FLAG_1 = 0x01,
FLAG_2 = 0x02,
FLAG_NONE = 0x00,
FLAG_ALL = 0xffffffffffffffffull
};

PARTICLE_DEFINE_FLAG_OPERATORS(FlagUint)
PARTICLE_DEFINE_FLAG_OPERATORS(FlagUint8)
PARTICLE_DEFINE_FLAG_OPERATORS(FlagUint64)

template<typename FlagsT>
void testFlags() {
using Flags = FlagsT;
using Enum = typename Flags::EnumType;
using Value = typename Flags::ValueType;

SECTION("Flags()") {
// Flags()
Flags f1;
CHECK(f1.value() == 0x00);
// Flags(ValueType)
Flags f2(0x01);
CHECK(f2.value() == 0x01);
// Flags(T)
Flags f3(Enum::FLAG_1);
CHECK(f3.value() == 0x01);
// Flags(const Flags&)
Flags f4(f3);
CHECK(f4.value() == f3.value());
}

SECTION("operator|()") {
// operator|(T, T)
Flags f1;
f1 = Enum::FLAG_NONE | Enum::FLAG_1;
CHECK(f1.value() == 0x01);
f1 = Enum::FLAG_1 | Enum::FLAG_1;
CHECK(f1.value() == 0x01);
f1 = Enum::FLAG_1 | Enum::FLAG_2;
CHECK(f1.value() == 0x03);
// operator|(T, Flags)
Flags f2;
f2 = Enum::FLAG_NONE | Flags(Enum::FLAG_1);
CHECK(f2.value() == 0x01);
f2 = Enum::FLAG_1 | Flags(Enum::FLAG_1);
CHECK(f2.value() == 0x01);
f2 = Enum::FLAG_1 | Flags(Enum::FLAG_2);
CHECK(f2.value() == 0x03);
// operator|(Flags, T)
Flags f3;
f3 = Flags(Enum::FLAG_NONE) | Enum::FLAG_1;
CHECK(f3.value() == 0x01);
f3 = Flags(Enum::FLAG_1) | Enum::FLAG_1;
CHECK(f3.value() == 0x01);
f3 = Flags(Enum::FLAG_1) | Enum::FLAG_2;
CHECK(f3.value() == 0x03);
// operator|(Flags, Flags)
Flags f4;
f4 = Flags(Enum::FLAG_NONE) | Flags(Enum::FLAG_1);
CHECK(f4.value() == 0x01);
f4 = Flags(Enum::FLAG_1) | Flags(Enum::FLAG_1);
CHECK(f4.value() == 0x01);
f4 = Flags(Enum::FLAG_1) | Flags(Enum::FLAG_2);
CHECK(f4.value() == 0x03);
}

SECTION("operator|=()") {
// operator|=(T)
Flags f1;
f1 |= Enum::FLAG_1;
CHECK(f1.value() == 0x01);
f1 |= Enum::FLAG_1;
CHECK(f1.value() == 0x01);
f1 |= Enum::FLAG_2;
CHECK(f1.value() == 0x03);
// operator|=(Flags)
Flags f2;
f2 |= Flags(Enum::FLAG_1);
CHECK(f2.value() == 0x01);
f2 |= Flags(Enum::FLAG_1);
CHECK(f2.value() == 0x01);
f2 |= Flags(Enum::FLAG_2);
CHECK(f2.value() == 0x03);
}

SECTION("operator&()") {
// operator&(T, Flags)
Flags f1;
f1 = Enum::FLAG_NONE & Flags(Enum::FLAG_1);
CHECK(f1.value() == 0x00);
f1 = Enum::FLAG_1 & Flags(Enum::FLAG_1);
CHECK(f1.value() == 0x01);
f1 = Enum::FLAG_1 & Flags(Enum::FLAG_2);
CHECK(f1.value() == 0x00);
// operator&(Flags, T)
Flags f2;
f2 = Flags(Enum::FLAG_NONE) & Enum::FLAG_1;
CHECK(f2.value() == 0x00);
f2 = Flags(Enum::FLAG_1) & Enum::FLAG_1;
CHECK(f2.value() == 0x01);
f2 = Flags(Enum::FLAG_1) & Enum::FLAG_2;
CHECK(f2.value() == 0x00);
// operator&(Flags, Flags)
Flags f3;
f3 = Flags(Enum::FLAG_NONE) & Flags(Enum::FLAG_1);
CHECK(f3.value() == 0x00);
f3 = Flags(Enum::FLAG_1) & Flags(Enum::FLAG_1);
CHECK(f3.value() == 0x01);
f3 = Flags(Enum::FLAG_1) & Flags(Enum::FLAG_2);
CHECK(f3.value() == 0x00);
}

SECTION("operator&=()") {
// operator&=(T)
Flags f1(0x03);
f1 &= Enum::FLAG_1;
CHECK(f1.value() == 0x01);
f1 &= Enum::FLAG_1;
CHECK(f1.value() == 0x01);
f1 &= Enum::FLAG_2;
CHECK(f1.value() == 0x00);
// operator&=(Flags)
Flags f2(0x03);
f2 &= Flags(Enum::FLAG_1);
CHECK(f2.value() == 0x01);
f2 &= Flags(Enum::FLAG_1);
CHECK(f2.value() == 0x01);
f2 &= Flags(Enum::FLAG_2);
CHECK(f2.value() == 0x00);
}

SECTION("operator^()") {
// operator^(T, Flags)
Flags f2;
f2 = Enum::FLAG_NONE ^ Flags(Enum::FLAG_1);
CHECK(f2.value() == 0x01);
f2 = Enum::FLAG_1 ^ Flags(Enum::FLAG_1);
CHECK(f2.value() == 0x00);
f2 = Enum::FLAG_1 ^ Flags(Enum::FLAG_2);
CHECK(f2.value() == 0x03);
// operator^(Flags, T)
Flags f3;
f3 = Flags(Enum::FLAG_NONE) ^ Enum::FLAG_1;
CHECK(f3.value() == 0x01);
f3 = Flags(Enum::FLAG_1) ^ Enum::FLAG_1;
CHECK(f3.value() == 0x00);
f3 = Flags(Enum::FLAG_1) ^ Enum::FLAG_2;
CHECK(f3.value() == 0x03);
// operator^(Flags, Flags)
Flags f4;
f4 = Flags(Enum::FLAG_NONE) ^ Flags(Enum::FLAG_1);
CHECK(f4.value() == 0x01);
f4 = Flags(Enum::FLAG_1) ^ Flags(Enum::FLAG_1);
CHECK(f4.value() == 0x00);
f4 = Flags(Enum::FLAG_1) ^ Flags(Enum::FLAG_2);
CHECK(f4.value() == 0x03);
}

SECTION("operator^=()") {
// operator^=(T)
Flags f1;
f1 ^= Enum::FLAG_1;
CHECK(f1.value() == 0x01);
f1 ^= Enum::FLAG_1;
CHECK(f1.value() == 0x00);
f1 ^= Enum::FLAG_2;
CHECK(f1.value() == 0x02);
// operator^=(Flags)
Flags f2;
f2 ^= Flags(Enum::FLAG_1);
CHECK(f2.value() == 0x01);
f2 ^= Flags(Enum::FLAG_1);
CHECK(f2.value() == 0x00);
f2 ^= Flags(Enum::FLAG_2);
CHECK(f2.value() == 0x02);
}

SECTION("operator~()") {
Flags f1 = ~Flags(Enum::FLAG_NONE);
CHECK(f1.value() == (Value)Enum::FLAG_ALL);
Flags f2 = ~Flags(Enum::FLAG_ALL);
CHECK(f2.value() == (Value)Enum::FLAG_NONE);
}

SECTION("operator=()") {
// operator=(T)
Flags f1;
f1 = Enum::FLAG_1;
CHECK(f1.value() == 0x01);
// operator=(Flags)
Flags f2;
f2 = Flags(Enum::FLAG_1);
CHECK(f2.value() == 0x01);
// operator=(ValueType)
Flags f3;
f3 = 0x01;
CHECK(f3.value() == 0x01);
}

SECTION("operator ValueType()") {
Flags f1(0x01);
CHECK((Value)f1 == 0x01);
CHECK(f1); // acts as implicit operator bool()
Flags f2;
CHECK((Value)f2 == 0x00);
CHECK_FALSE(f2);
}

SECTION("operator!()") {
Flags f1(0x01);
CHECK_FALSE(!f1);
Flags f2;
CHECK(!f2);
}

SECTION("underlying type fits all flag values") {
Flags f1(Enum::FLAG_ALL);
CHECK(f1.value() == (Value)Enum::FLAG_ALL);
Flags f2((Value)Enum::FLAG_ALL);
CHECK(f2.value() == (Value)Enum::FLAG_ALL);
Flags f3;
f3 = (Value)Enum::FLAG_ALL;
CHECK(f3.value() == (Value)Enum::FLAG_ALL);
}
}

} // namespace

TEST_CASE("Flags<T>") {
testFlags<Flags<FlagUint>>();
testFlags<Flags<FlagUint8>>();
testFlags<Flags<FlagUint64>>();
}
2 changes: 2 additions & 0 deletions user/tests/unit/tools/catch.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

// Non-prefixed aliases for some typical macros that don't clash with the firmware
#define CHECK(...) CATCH_CHECK(__VA_ARGS__)
#define CHECK_FALSE(...) CATCH_CHECK_FALSE(__VA_ARGS__)
#define REQUIRE(...) CATCH_REQUIRE(__VA_ARGS__)
#define REQUIRE_FALSE(...) CATCH_REQUIRE_FALSE(__VA_ARGS__)
#define FAIL(...) CATCH_FAIL(__VA_ARGS__)
#define TEST_CASE(...) CATCH_TEST_CASE(__VA_ARGS__)
#define SECTION(...) CATCH_SECTION(__VA_ARGS__)
Expand Down
71 changes: 32 additions & 39 deletions user/tests/wiring/api/cloud.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ test(api_spark_variable) {
API_COMPILE(Particle.variable("mystring", valueString));
API_COMPILE(Particle.variable("mystring", constValueString));
API_COMPILE(Particle.variable("mystring", valueSmartString));

// This should gives a compiler error about too long name
//API_COMPILE(Particle.variable("mystring123456789", valueString));

Expand All @@ -91,44 +91,37 @@ test(api_spark_function) {
}

test(api_spark_publish) {

API_COMPILE(Particle.publish("public event name"));

API_COMPILE(Particle.publish("public event name", "event data"));

API_COMPILE(Particle.publish("public event name", "event data"));

API_COMPILE(Particle.publish("public event name", "event data", 60));

API_COMPILE(Particle.publish("public event name", "event data", 60, PUBLIC));

API_COMPILE(Particle.publish("private event name", "event data", 60, PRIVATE));

API_COMPILE(Particle.publish("public event name", PRIVATE));

API_COMPILE(Particle.publish("public event name", "event data", PRIVATE));

API_COMPILE(Particle.publish("public event name", PUBLIC));


API_COMPILE(Particle.publish(String("public event name")));

API_COMPILE(Particle.publish(String("public event name"), String("event data")));

API_COMPILE(Particle.publish(String("public event name"), String("event data")));

API_COMPILE(Particle.publish(String("public event name"), String("event data"), 60));

API_COMPILE(Particle.publish(String("public event name"), String("event data"), 60, PUBLIC));

API_COMPILE(Particle.publish(String("public event name"), String("event data"), 60, PRIVATE));

API_COMPILE(Particle.publish(String("public event name"), PRIVATE));

API_COMPILE(Particle.publish(String("public event name"), String("event data"), PRIVATE));

API_COMPILE(Particle.publish(String("public event name"), PUBLIC));

// Particle.publish(const char*, const char*, ...)
API_COMPILE(Particle.publish("event"));
API_COMPILE(Particle.publish("event", PUBLIC));
API_COMPILE(Particle.publish("event", PUBLIC, NO_ACK));
API_COMPILE(Particle.publish("event", PUBLIC | NO_ACK)); // traditional syntax

API_COMPILE(Particle.publish("event", "data"));
API_COMPILE(Particle.publish("event", "data", PUBLIC));
API_COMPILE(Particle.publish("event", "data", PUBLIC, NO_ACK));
API_COMPILE(Particle.publish("event", "data", PUBLIC | NO_ACK));

API_COMPILE(Particle.publish("event", "data", 60));
API_COMPILE(Particle.publish("event", "data", 60, PUBLIC));
API_COMPILE(Particle.publish("event", "data", 60, PUBLIC, NO_ACK));
API_COMPILE(Particle.publish("event", "data", 60, PUBLIC | NO_ACK));

// Particle.publish(String, String, ...)
API_COMPILE(Particle.publish(String("event")));
API_COMPILE(Particle.publish(String("event"), PUBLIC));
API_COMPILE(Particle.publish(String("event"), PUBLIC, NO_ACK));
API_COMPILE(Particle.publish(String("event"), PUBLIC | NO_ACK));

API_COMPILE(Particle.publish(String("event"), String("data")));
API_COMPILE(Particle.publish(String("event"), String("data"), PUBLIC));
API_COMPILE(Particle.publish(String("event"), String("data"), PUBLIC, NO_ACK));
API_COMPILE(Particle.publish(String("event"), String("data"), PUBLIC | NO_ACK));

API_COMPILE(Particle.publish(String("event"), String("data"), 60));
API_COMPILE(Particle.publish(String("event"), String("data"), 60, PUBLIC));
API_COMPILE(Particle.publish(String("event"), String("data"), 60, PUBLIC, NO_ACK));
API_COMPILE(Particle.publish(String("event"), String("data"), 60, PUBLIC | NO_ACK));
}

test(api_spark_subscribe) {
Expand Down
Loading

0 comments on commit 7bf2aa8

Please sign in to comment.