pw_assert: Initial assert module

This starts the assert and assert_basic modules, which are the beginning
of our assert foundation. Much more is needed; in particular the "tests"
don't really do much other than check for compilation.

Screenshot
==========

   ▄████▄      ██▀███      ▄▄▄           ██████     ██░ ██
  ▒██▀ ▀█     ▓██ ▒ ██▒   ▒████▄       ▒██    ▒    ▓██░ ██▒
  ▒▓█ 💥 ▄    ▓██ ░▄█ ▒   ▒██  ▀█▄     ░ ▓██▄      ▒██▀▀██░
  ▒▓▓▄ ▄██▒   ▒██▀▀█▄     ░██▄▄▄▄██      ▒   ██▒   ░▓█ ░██
  ▒ ▓███▀ ░   ░██▓ ▒██▒    ▓█   ▓██▒   ▒██████▒▒   ░▓█▒░██▓
  ░ ░▒ ▒  ░   ░ ▒▓ ░▒▓░    ▒▒   ▓▒█░   ▒ ▒▓▒ ▒ ░    ▒ ░░▒░▒
    ░  ▒        ░▒ ░ ▒░     ▒   ▒▒ ░   ░ ░▒  ░ ░    ▒ ░▒░ ░
  ░             ░░   ░      ░   ▒      ░  ░  ░      ░  ░░ ░
  ░ ░            ░              ░  ░         ░      ░  ░  ░
  ░

  Welp, that didn't go as planned. It seems we crashed. Terribly sorry!

  CRASH MESSAGE

     Check failed: x (=50) > y (=51300): You SHOULD see this message

  CRASH FILE & LINE

     ../../pw_assert/assert_test.cc:46

  CRASH FUNCTION

     PigweedTestBody

==========

Change-Id: I9dbb460b3b33040d8009749f44b9fc174e2c8138
diff --git a/pw_assert/assert_test.cc b/pw_assert/assert_test.cc
new file mode 100644
index 0000000..89cd39b
--- /dev/null
+++ b/pw_assert/assert_test.cc
@@ -0,0 +1,169 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+// This is mostly a compile test to verify that the log backend is able to
+// compile the constructs promised by the logging facade; and that when run,
+// there is no crash.
+//
+// TODO(pwbug/88): Add verification of the actually logged statements.
+
+// clang-format off
+#include "pw_assert/assert.h"
+// clang-format on
+
+#include "gtest/gtest.h"
+
+// This is a global constant to feed into the formatter for tests.
+// Intended to pair with FAIL_IF_DISPLAYED_ARGS or FAIL_IF_HIDDEN_ARGS.
+static const int z = 10;
+
+// At some point in the future when there is a proper test system in place for
+// crashing, the below strings can help indicate pass/fail for a check.
+
+#define FAIL_IF_DISPLAYED "FAIL IF DISPLAYED"
+#define FAIL_IF_DISPLAYED_ARGS "FAIL IF DISPLAYED: %d"
+
+#define FAIL_IF_HIDDEN "FAIL IF HIDDEN"
+#define FAIL_IF_HIDDEN_ARGS "FAIL IF HIDDEN: %d"
+
+// This switch exists to support compiling and/or running the tests.
+#define DISABLE_ASSERT_TEST_EXECUTION 1
+#if DISABLE_ASSERT_TEST_EXECUTION
+#define MAYBE_SKIP_TEST return
+#else
+#define MAYBE_SKIP_TEST ;
+#endif
+
+namespace {
+
+TEST(Crash, WithAndWithoutMessageArguments) {
+  MAYBE_SKIP_TEST;
+  PW_CRASH(FAIL_IF_HIDDEN);
+  PW_CRASH(FAIL_IF_HIDDEN_ARGS, z);
+}
+
+TEST(Check, NoMessage) {
+  MAYBE_SKIP_TEST;
+  PW_CHECK(true);
+  PW_CHECK(false);
+}
+
+TEST(Check, WithMessageAndArgs) {
+  MAYBE_SKIP_TEST;
+  PW_CHECK(true, FAIL_IF_DISPLAYED);
+  PW_CHECK(true, FAIL_IF_DISPLAYED_ARGS, z);
+
+  PW_CHECK(false, FAIL_IF_HIDDEN);
+  PW_CHECK(false, FAIL_IF_HIDDEN_ARGS, z);
+}
+
+TEST(Check, IntComparison) {
+  MAYBE_SKIP_TEST;
+  int x_int = 50;
+  int y_int = 66;
+
+  PW_CHECK_INT_LE(x_int, y_int);
+  PW_CHECK_INT_LE(x_int, y_int, "INT: " FAIL_IF_DISPLAYED);
+  PW_CHECK_INT_LE(x_int, y_int, "INT: " FAIL_IF_DISPLAYED_ARGS, z);
+
+  PW_CHECK_INT_GE(x_int, y_int);
+  PW_CHECK_INT_GE(x_int, y_int, "INT: " FAIL_IF_HIDDEN);
+  PW_CHECK_INT_GE(x_int, y_int, "INT: " FAIL_IF_HIDDEN_ARGS, z);
+}
+
+TEST(Check, UintComparison) {
+  MAYBE_SKIP_TEST;
+  unsigned int x_uint = 50;
+  unsigned int y_uint = 66;
+
+  PW_CHECK_UINT_LE(x_uint, y_uint);
+  PW_CHECK_UINT_LE(x_uint, y_uint, "UINT: " FAIL_IF_DISPLAYED);
+  PW_CHECK_UINT_LE(x_uint, y_uint, "UINT: " FAIL_IF_DISPLAYED_ARGS, z);
+
+  PW_CHECK_UINT_GE(x_uint, y_uint);
+  PW_CHECK_UINT_GE(x_uint, y_uint, "UINT: " FAIL_IF_HIDDEN);
+  PW_CHECK_UINT_GE(x_uint, y_uint, "UINT: " FAIL_IF_HIDDEN_ARGS, z);
+}
+
+TEST(Check, FloatComparison) {
+  MAYBE_SKIP_TEST;
+  float x_float = 50.5;
+  float y_float = 66.5;
+
+  PW_CHECK_FLOAT_LE(x_float, y_float);
+  PW_CHECK_FLOAT_LE(x_float, y_float, "FLOAT: " FAIL_IF_DISPLAYED);
+  PW_CHECK_FLOAT_LE(x_float, y_float, "FLOAT: " FAIL_IF_DISPLAYED_ARGS, z);
+
+  PW_CHECK_FLOAT_GE(x_float, y_float);
+  PW_CHECK_FLOAT_GE(x_float, y_float, "FLOAT: " FAIL_IF_HIDDEN);
+  PW_CHECK_FLOAT_GE(x_float, y_float, "FLOAT: " FAIL_IF_HIDDEN_ARGS, z);
+}
+
+static int Add3(int a, int b, int c) { return a + b + c; }
+
+TEST(Check, ComparisonArgumentsWithCommas) {
+  MAYBE_SKIP_TEST;
+  int x_int = 50;
+  int y_int = 66;
+
+  PW_CHECK_INT_LE(Add3(1, 2, 3), y_int);
+  PW_CHECK_INT_LE(x_int, Add3(1, 2, 3));
+
+  PW_CHECK_INT_LE(Add3(1, 2, 3), y_int, FAIL_IF_DISPLAYED);
+  PW_CHECK_INT_LE(x_int, Add3(1, 2, 3), FAIL_IF_DISPLAYED_ARGS, z);
+
+  PW_CHECK_INT_LE(Add3(1, 2, 3), Add3(1, 2, 3), "INT: " FAIL_IF_DISPLAYED);
+  PW_CHECK_INT_LE(x_int, y_int, "INT: " FAIL_IF_DISPLAYED_ARGS, z);
+}
+
+// These are defined in assert_test.c, to test C compatibility.
+extern "C" {
+void AssertTestsInC();
+}  // extern "C"
+
+TEST(Check, AssertTestsInC) {
+  MAYBE_SKIP_TEST;
+  AssertTestsInC();
+}
+
+static int global_state_for_multi_evaluate_test;
+static int IncrementsGlobal() {
+  global_state_for_multi_evaluate_test++;
+  return 0;
+}
+
+// This test verifies that the binary CHECK_*(x,y) macros only
+// evaluate their arguments once.
+TEST(Check, BinaryOpOnlyEvaluatesOnce) {
+  MAYBE_SKIP_TEST;
+
+  global_state_for_multi_evaluate_test = 0;
+  PW_CHECK_INT_EQ(0, IncrementsGlobal());
+  EXPECT_EQ(global_state_for_multi_evaluate_test, 1);
+
+  global_state_for_multi_evaluate_test = 0;
+  PW_CHECK_INT_EQ(IncrementsGlobal(), IncrementsGlobal());
+  EXPECT_EQ(global_state_for_multi_evaluate_test, 2);
+
+  // Fails; should only evaluate IncrementGlobal() once.
+  global_state_for_multi_evaluate_test = 0;
+  PW_CHECK_INT_EQ(1, IncrementsGlobal());
+  EXPECT_EQ(global_state_for_multi_evaluate_test, 1);
+
+  global_state_for_multi_evaluate_test = 0;
+  PW_CHECK_INT_EQ(IncrementsGlobal(), 1 + IncrementsGlobal());
+  EXPECT_EQ(global_state_for_multi_evaluate_test, 2);
+}
+
+}  // namespace