pw_unit_test: Check test suite names

- Check that test suite names do not contain underscores during
  compilation. Underscores in test names are not permitted by Google
  Test.
- Remove unnecessary use of PW_CONCAT macro.
- Add missing include for PW_CONCAT to pw_trace.

Change-Id: Id50f855b32c1b51f3da398c6c4ea07aaece20b3a
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/68596
Pigweed-Auto-Submit: Wyatt Hepler <hepler@google.com>
Reviewed-by: Armando Montanez <amontanez@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
diff --git a/pw_assert/pw_assert_test/fake_backend.h b/pw_assert/pw_assert_test/fake_backend.h
index ee7f3be..869d224 100644
--- a/pw_assert/pw_assert_test/fake_backend.h
+++ b/pw_assert/pw_assert_test/fake_backend.h
@@ -15,6 +15,7 @@
 
 #include <stdbool.h>
 
+#include "pw_preprocessor/arguments.h"
 #include "pw_preprocessor/compiler.h"
 #include "pw_preprocessor/util.h"
 
diff --git a/pw_assert_basic/public/pw_assert_basic/assert_basic.h b/pw_assert_basic/public/pw_assert_basic/assert_basic.h
index cc933d0..88405f8 100644
--- a/pw_assert_basic/public/pw_assert_basic/assert_basic.h
+++ b/pw_assert_basic/public/pw_assert_basic/assert_basic.h
@@ -14,6 +14,7 @@
 #pragma once
 
 #include "pw_assert_basic/handler.h"
+#include "pw_preprocessor/arguments.h"
 #include "pw_preprocessor/compiler.h"
 #include "pw_preprocessor/util.h"
 
diff --git a/pw_trace/public/pw_trace/internal/trace_internal.h b/pw_trace/public/pw_trace/internal/trace_internal.h
index f3604db..18e51a7 100644
--- a/pw_trace/public/pw_trace/internal/trace_internal.h
+++ b/pw_trace/public/pw_trace/internal/trace_internal.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include "pw_preprocessor/arguments.h"
+#include "pw_preprocessor/concat.h"
 #include "pw_trace_backend/trace_backend.h"
 
 // Default: Flag value if none set
diff --git a/pw_unit_test/public/pw_unit_test/framework.h b/pw_unit_test/public/pw_unit_test/framework.h
index e609e84..8b24726 100644
--- a/pw_unit_test/public/pw_unit_test/framework.h
+++ b/pw_unit_test/public/pw_unit_test/framework.h
@@ -24,7 +24,6 @@
 #include <span>
 
 #include "pw_polyfill/standard.h"
-#include "pw_preprocessor/concat.h"
 #include "pw_preprocessor/util.h"
 #include "pw_unit_test/config.h"
 #include "pw_unit_test/event_handler.h"
@@ -417,6 +416,23 @@
   virtual void PigweedTestBody() = 0;
 };
 
+// Checks that a test suite name is valid.
+constexpr bool HasNoUnderscores(const char* suite) {
+  const char* disabled_prefix = "DISABLED_";
+
+  for (; *suite != '\0'; ++suite) {
+    if (*suite == *disabled_prefix) {
+      disabled_prefix += 1;
+    } else {
+      disabled_prefix = "";
+      if (*suite == '_') {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
 }  // namespace internal
 
 #if PW_CXX_STANDARD_IS_SUPPORTED(17)
@@ -428,31 +444,34 @@
 }  // namespace unit_test
 }  // namespace pw
 
-#define _PW_TEST_CLASS_NAME(test_suite_name, test_name) \
-  PW_CONCAT(test_suite_name, _, test_name, _Test)
+#define _PW_TEST(test_suite_name, test_name, parent_class)                     \
+  static_assert(sizeof(#test_suite_name) > 1,                                  \
+                "The test suite name must not be empty");                      \
+  static_assert(::pw::unit_test::internal::HasNoUnderscores(#test_suite_name), \
+                "The test suite name (" #test_suite_name                       \
+                ") cannot contain underscores");                               \
+  static_assert(sizeof(#test_name) > 1, "The test name must not be empty");    \
+                                                                               \
+  _PW_TEST_CLASS(test_suite_name,                                              \
+                 test_name,                                                    \
+                 test_suite_name##_##test_name##_Test,                         \
+                 parent_class)
 
-#define _PW_TEST(test_suite_name, test_name, parent_class)              \
-  static_assert(sizeof(#test_suite_name) > 1,                           \
-                "test_suite_name must not be empty");                   \
-  static_assert(sizeof(#test_name) > 1, "test_name must not be empty"); \
-                                                                        \
-  class _PW_TEST_CLASS_NAME(test_suite_name, test_name) final           \
-      : public parent_class {                                           \
-   private:                                                             \
-    void PigweedTestBody() override;                                    \
-                                                                        \
-    static ::pw::unit_test::internal::TestInfo test_info_;              \
-  };                                                                    \
-                                                                        \
-  ::pw::unit_test::internal::TestInfo                                   \
-      _PW_TEST_CLASS_NAME(test_suite_name, test_name)::test_info_(      \
-          #test_suite_name,                                             \
-          #test_name,                                                   \
-          __FILE__,                                                     \
-          ::pw::unit_test::internal::Framework::CreateAndRunTest<       \
-              _PW_TEST_CLASS_NAME(test_suite_name, test_name)>);        \
-                                                                        \
-  void _PW_TEST_CLASS_NAME(test_suite_name, test_name)::PigweedTestBody()
+#define _PW_TEST_CLASS(suite, name, class_name, parent_class)              \
+  class class_name final : public parent_class {                           \
+   private:                                                                \
+    void PigweedTestBody() override;                                       \
+                                                                           \
+    static ::pw::unit_test::internal::TestInfo test_info_;                 \
+  };                                                                       \
+                                                                           \
+  ::pw::unit_test::internal::TestInfo class_name::test_info_(              \
+      #suite,                                                              \
+      #name,                                                               \
+      __FILE__,                                                            \
+      ::pw::unit_test::internal::Framework::CreateAndRunTest<class_name>); \
+                                                                           \
+  void class_name::PigweedTestBody()
 
 #define _PW_TEST_ASSERT(expectation) \
   do {                               \