From 64d1e6bbc4b5ee11b84e58f416fc285dbebc4f09 Mon Sep 17 00:00:00 2001 From: zxu Date: Mon, 8 Jan 2018 20:48:28 -0500 Subject: implement C++ assert (stdio, apple) (#612) * implement C++ assert (stdio, apple) * Update tests for firebase_firestore_util renames * renaming `assert.h` to `firebase_assert.h` * refactoring to a common `WrapNSStringNoCopy()` --- .../src/firebase/firestore/util/CMakeLists.txt | 4 +- .../src/firebase/firestore/util/assert_apple.mm | 44 +++++++++ .../src/firebase/firestore/util/assert_stdio.cc | 53 +++++++++++ .../src/firebase/firestore/util/firebase_assert.h | 102 +++++++++++++++++++++ .../core/src/firebase/firestore/util/log_apple.mm | 21 ++--- .../src/firebase/firestore/util/string_apple.h | 39 ++++++++ .../test/firebase/firestore/util/CMakeLists.txt | 2 + .../test/firebase/firestore/util/assert_test.cc | 64 +++++++++++++ 8 files changed, 314 insertions(+), 15 deletions(-) create mode 100644 Firestore/core/src/firebase/firestore/util/assert_apple.mm create mode 100644 Firestore/core/src/firebase/firestore/util/assert_stdio.cc create mode 100644 Firestore/core/src/firebase/firestore/util/firebase_assert.h create mode 100644 Firestore/core/src/firebase/firestore/util/string_apple.h create mode 100644 Firestore/core/test/firebase/firestore/util/assert_test.cc (limited to 'Firestore') diff --git a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt index a2da3b4..3028a95 100644 --- a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt +++ b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt @@ -23,13 +23,14 @@ add_library( ) target_link_libraries( firebase_firestore_util_base - PRIVATE + PUBLIC absl_base ) # stdio-dependent bits can be built and tested everywhere add_library( firebase_firestore_util_stdio + assert_stdio.cc log_stdio.cc ) target_link_libraries( @@ -42,6 +43,7 @@ target_link_libraries( if(APPLE) add_library( firebase_firestore_util_apple + assert_apple.mm log_apple.mm ) target_compile_options( diff --git a/Firestore/core/src/firebase/firestore/util/assert_apple.mm b/Firestore/core/src/firebase/firestore/util/assert_apple.mm new file mode 100644 index 0000000..0447d6c --- /dev/null +++ b/Firestore/core/src/firebase/firestore/util/assert_apple.mm @@ -0,0 +1,44 @@ +/* + * Copyright 2018 Google + * + * 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 + * + * http://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. + */ + +#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h" + +#import + +#include + +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" + +namespace firebase { +namespace firestore { +namespace util { + +void FailAssert(const char* file, const char* func, const int line, const char* format, ...) { + va_list args; + va_start(args, format); + NSString *description = [[NSString alloc] initWithFormat:WrapNSStringNoCopy(format) arguments:args]; + va_end(args); + [[NSAssertionHandler currentHandler] + handleFailureInFunction:WrapNSStringNoCopy(func) + file:WrapNSStringNoCopy(file) + lineNumber:line + description:@"FIRESTORE INTERNAL ASSERTION FAILED: %@", description]; + abort(); +} + +} // namespace util +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/src/firebase/firestore/util/assert_stdio.cc b/Firestore/core/src/firebase/firestore/util/assert_stdio.cc new file mode 100644 index 0000000..b5d0b7c --- /dev/null +++ b/Firestore/core/src/firebase/firestore/util/assert_stdio.cc @@ -0,0 +1,53 @@ +/* + * Copyright 2018 Google + * + * 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 + * + * http://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. + */ + +#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h" + +#include + +#include +#include + +#include + +#include "Firestore/core/src/firebase/firestore/util/string_printf.h" + +namespace firebase { +namespace firestore { +namespace util { + +void FailAssert(const char* file, const char* func, const int line, + const char* format, ...) { + std::string message; + StringAppendF(&message, "ASSERT: %s(%d) %s: ", file, line, func); + + va_list args; + va_start(args, format); + StringAppendV(&message, format, args); + va_end(args); + +#if ABSL_HAVE_EXCEPTIONS + throw std::logic_error(message); + +#else + fprintf(stderr, "%s\n", message.c_str()); + std::terminate(); +#endif +} + +} // namespace util +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/src/firebase/firestore/util/firebase_assert.h b/Firestore/core/src/firebase/firestore/util/firebase_assert.h new file mode 100644 index 0000000..9f1bce8 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/util/firebase_assert.h @@ -0,0 +1,102 @@ +/* + * Copyright 2018 Google + * + * 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 + * + * http://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. + */ + +// To avoid naming-collision, this header is called firebase_assert.h instead +// of assert.h. + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_FIREBASE_ASSERT_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_FIREBASE_ASSERT_H_ + +#include + +#include "Firestore/core/src/firebase/firestore/util/log.h" + +#define FIREBASE_EXPAND_STRINGIFY_(X) #X +#define FIREBASE_EXPAND_STRINGIFY(X) FIREBASE_EXPAND_STRINGIFY_(X) + +// FIREBASE_ASSERT_* macros are not compiled out of release builds. They should +// be used for assertions that need to be propagated to end-users of SDKs. +// FIREBASE_DEV_ASSERT_* macros are compiled out of release builds, similar to +// the C assert() macro. They should be used for internal assertions that are +// only shown to SDK developers. + +// Assert condition is true, if it's false log an assert with the specified +// expression as a string. +#define FIREBASE_ASSERT_WITH_EXPRESSION(condition, expression) \ + do { \ + if (!(condition)) { \ + firebase::firestore::util::FailAssert( \ + __FILE__, __PRETTY_FUNCTION__, __LINE__, \ + FIREBASE_EXPAND_STRINGIFY(expression)); \ + } \ + } while(0) + +// Assert condition is true, if it's false log an assert with the specified +// expression as a string. Compiled out of release builds. +#if defined(NDEBUG) +#define FIREBASE_DEV_ASSERT_WITH_EXPRESSION(condition, expression) \ + { (void)(condition); } +#else +#define FIREBASE_DEV_ASSERT_WITH_EXPRESSION(condition, expression) \ + FIREBASE_ASSERT_WITH_EXPRESSION(condition, expression) +#endif // !defined(NDEBUG) + +// Custom assert() implementation that is not compiled out in release builds. +#define FIREBASE_ASSERT(expression) \ + FIREBASE_ASSERT_WITH_EXPRESSION(expression, expression) + +// Custom assert() implementation that is compiled out in release builds. +// Compiled out of release builds. +#define FIREBASE_DEV_ASSERT(expression) \ + FIREBASE_DEV_ASSERT_WITH_EXPRESSION(expression, expression) + +// Assert condition is true otherwise display the specified expression, +// message and abort. +#define FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(condition, expression, ...) \ + do { \ + if (!(condition)) { \ + firebase::firestore::util::LogError( \ + FIREBASE_EXPAND_STRINGIFY(expression)); \ + firebase::firestore::util::FailAssert( \ + __FILE__, __PRETTY_FUNCTION__, __LINE__, __VA_ARGS__); \ + } \ + } while(0) + +// Assert condition is true otherwise display the specified expression, +// message and abort. Compiled out of release builds. +#if defined(NDEBUG) +#define FIREBASE_DEV_ASSERT_MESSAGE_WITH_EXPRESSION(condition, expression, \ + ...) \ + { (void)(condition); } +#else +#define FIREBASE_DEV_ASSERT_MESSAGE_WITH_EXPRESSION(condition, expression, \ + ...) \ + FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(condition, expression, __VA_ARGS__) +#endif // !defined(NDEBUG) + +namespace firebase { +namespace firestore { +namespace util { + +// A no-return helper function. To raise an assertion, use Macro instead. +void FailAssert(const char* file, const char* func, const int line, + const char* format, ...); + +} // namespace util +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_FIREBASE_ASSERT_H_ diff --git a/Firestore/core/src/firebase/firestore/util/log_apple.mm b/Firestore/core/src/firebase/firestore/util/log_apple.mm index afa087f..cb2c58e 100644 --- a/Firestore/core/src/firebase/firestore/util/log_apple.mm +++ b/Firestore/core/src/firebase/firestore/util/log_apple.mm @@ -21,21 +21,14 @@ #include +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" + namespace firebase { namespace firestore { namespace util { namespace { -// Translates a C format string to the equivalent NSString without making a -// copy. -NSString* FormatString(const char* format) { - return [[NSString alloc] initWithBytesNoCopy:(void*)format - length:strlen(format) - encoding:NSUTF8StringEncoding - freeWhenDone:NO]; -} - // Translates a C++ LogLevel to the equivalent Objective-C FIRLoggerLevel FIRLoggerLevel ToFIRLoggerLevel(LogLevel level) { switch (level) { @@ -85,7 +78,7 @@ void LogDebug(const char* format, ...) { va_list list; va_start(list, format); FIRLogBasic(FIRLoggerLevelDebug, kFIRLoggerFirestore, @"I-FST000001", - FormatString(format), list); + WrapNSStringNoCopy(format), list); va_end(list); } @@ -93,7 +86,7 @@ void LogInfo(const char* format, ...) { va_list list; va_start(list, format); FIRLogBasic(FIRLoggerLevelInfo, kFIRLoggerFirestore, @"I-FST000001", - FormatString(format), list); + WrapNSStringNoCopy(format), list); va_end(list); } @@ -101,7 +94,7 @@ void LogWarning(const char* format, ...) { va_list list; va_start(list, format); FIRLogBasic(FIRLoggerLevelWarning, kFIRLoggerFirestore, @"I-FST000001", - FormatString(format), list); + WrapNSStringNoCopy(format), list); va_end(list); } @@ -109,13 +102,13 @@ void LogError(const char* format, ...) { va_list list; va_start(list, format); FIRLogBasic(FIRLoggerLevelError, kFIRLoggerFirestore, @"I-FST000001", - FormatString(format), list); + WrapNSStringNoCopy(format), list); va_end(list); } void LogMessageV(LogLevel log_level, const char* format, va_list args) { FIRLogBasic(ToFIRLoggerLevel(log_level), kFIRLoggerFirestore, @"I-FST000001", - FormatString(format), args); + WrapNSStringNoCopy(format), args); } void LogMessage(LogLevel log_level, const char* format, ...) { diff --git a/Firestore/core/src/firebase/firestore/util/string_apple.h b/Firestore/core/src/firebase/firestore/util/string_apple.h new file mode 100644 index 0000000..42b51dd --- /dev/null +++ b/Firestore/core/src/firebase/firestore/util/string_apple.h @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Google + * + * 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 + * + * http://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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_APPLE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_APPLE_H_ + +#import + +namespace firebase { +namespace firestore { +namespace util { + +// Translates a C string to the equivalent NSString without making a copy. +inline NSString* WrapNSStringNoCopy(const char* c_str) { + return [[NSString alloc] initWithBytesNoCopy:const_cast(static_cast(c_str)) + length:strlen(c_str) + encoding:NSUTF8StringEncoding + freeWhenDone:NO]; +} + + +} // namespace util +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_APPLE_H_ diff --git a/Firestore/core/test/firebase/firestore/util/CMakeLists.txt b/Firestore/core/test/firebase/firestore/util/CMakeLists.txt index 5e10715..e51bb51 100644 --- a/Firestore/core/test/firebase/firestore/util/CMakeLists.txt +++ b/Firestore/core/test/firebase/firestore/util/CMakeLists.txt @@ -26,6 +26,7 @@ target_link_libraries( if(APPLE) cc_test( firebase_firestore_util_apple_test + assert_test.cc log_test.cc ) target_link_libraries( @@ -36,6 +37,7 @@ endif(APPLE) cc_test( firebase_firestore_util_stdio_test + assert_test.cc log_test.cc ) target_link_libraries( diff --git a/Firestore/core/test/firebase/firestore/util/assert_test.cc b/Firestore/core/test/firebase/firestore/util/assert_test.cc new file mode 100644 index 0000000..7c49462 --- /dev/null +++ b/Firestore/core/test/firebase/firestore/util/assert_test.cc @@ -0,0 +1,64 @@ +/* + * Copyright 2018 Google + * + * 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 + * + * http://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. + */ + +#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h" + +#include + +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { +namespace util { + +namespace { + +void AssertWithExpression(bool condition) { + FIREBASE_ASSERT_WITH_EXPRESSION(condition, 1 + 2 + 3); +} + +void Assert(bool condition) { + FIREBASE_ASSERT(condition == true); +} + +void AssertMessageWithExpression(bool condition) { + FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(condition, 1 + 2 + 3, "connection %s", + condition ? "succeeded" : "failed"); +} + +} // namespace + +TEST(Assert, WithExpression) { + AssertWithExpression(true); + + EXPECT_ANY_THROW(AssertWithExpression(false)); +} + +TEST(Assert, Vanilla) { + Assert(true); + + EXPECT_ANY_THROW(Assert(false)); +} + +TEST(Assert, WithMessageAndExpression) { + AssertMessageWithExpression(true); + + EXPECT_ANY_THROW(AssertMessageWithExpression(false)); +} + +} // namespace util +} // namespace firestore +} // namespace firebase -- cgit v1.2.3