/*
* Copyright (C) 2016 The Android Open Source Project
*
* 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 <shared/nano_string.h>
#include <string.h> // brings strlen, strncpy, and memset into scope.
#include <stdint.h>
#include <gtest/gtest.h>
#include <shared/array_length.h>
// This "using directive" intentionally makes the symbols 'strlen', 'strncpy',
// and 'memset' "ambigious" at this point. This means that every use of these
// needs to be fully qualified in our tests below. That's as desired for
// clarity and to avoid accidentally invoking the wrong version.
// Note that a leading bare "::" is the fully qualified version of the
// C library methods.
using namespace nanoapp_testing;
static constexpr size_t kMemsetBufferLen = 16;
static constexpr int kUnsetValue = 0x5F;
static constexpr int kNewValue = 0xB8;
template<size_t kLenToSet>
static void testMemset() {
uint8_t expected[kMemsetBufferLen];
uint8_t actual[arrayLength(expected)];
static_assert(kLenToSet <= arrayLength(expected), "Bad test invocation");
::memset(expected, kUnsetValue, sizeof(expected));
::memset(actual, kUnsetValue, sizeof(actual));
::memset(expected, kNewValue, kLenToSet);
nanoapp_testing::memset(actual, kNewValue, kLenToSet);
EXPECT_EQ(0, memcmp(expected, actual, sizeof(expected)));
}
TEST(NanoStringsTest, MemsetZeroBytes) {
testMemset<0>();
}
TEST(NanoStringsTest, MemsetPartialArray) {
testMemset<(kMemsetBufferLen / 2) - 1>();
}
TEST(NanoStringsTest, MemsetFullArray) {
testMemset<kMemsetBufferLen>();
}
static constexpr size_t kMemcpyBufferLen = 8;
static constexpr uint8_t kMemcpySrc[kMemcpyBufferLen] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
template<size_t kLenToCopy>
static void testMemcpy() {
uint8_t expected[arrayLength(kMemcpySrc)];
uint8_t actual[arrayLength(expected)];
static_assert(kLenToCopy <= arrayLength(kMemcpySrc), "Bad test invocation");
::memset(expected, kUnsetValue, sizeof(expected));
::memset(actual, kUnsetValue, sizeof(actual));
::memcpy(expected, kMemcpySrc, kLenToCopy);
nanoapp_testing::memcpy(actual, kMemcpySrc, kLenToCopy);
EXPECT_EQ(0, memcmp(expected, actual, sizeof(expected)));
}
TEST(NanoStringsTest, MemcpyZeroBytes) {
testMemcpy<0>();
}
TEST(NanoStringsTest, MemcpyPartialArray) {
testMemcpy<(kMemcpyBufferLen / 2) - 1>();
}
TEST(NanoStringsTest, MemcpyFullArray) {
testMemcpy<kMemcpyBufferLen>();
}
TEST(NanoStringsTest, StrlenEmptyString) {
const char *str = "";
EXPECT_EQ(::strlen(str), nanoapp_testing::strlen(str));
}
TEST(NanoStringsTest, StrlenNormal) {
const char *str = "random string\n";
EXPECT_EQ(::strlen(str), nanoapp_testing::strlen(str));
}
static constexpr size_t kStrncpyMax = 10;
static constexpr char kShortString[] = "short";
static constexpr char kLongString[] = "Kind of long string";
static constexpr char kExactString[] = "0123456789";
static void testStrncpy(const char *str, size_t len) {
char expected[kStrncpyMax];
char actual[arrayLength(expected)];
::memset(expected, kUnsetValue, sizeof(expected));
::memset(actual, kUnsetValue, sizeof(actual));
::strncpy(expected, str, len);
nanoapp_testing::strncpy(actual, str, len);
EXPECT_EQ(0, memcmp(expected, actual, sizeof(expected)));
}
TEST(NanoStringsTest, Strncpy) {
testStrncpy(kShortString, ::strlen(kShortString));
}
TEST(NanoStringsTest, StrncpySetsTrailingBytes) {
ASSERT_LT(::strlen(kShortString), kStrncpyMax);
testStrncpy(kShortString, kStrncpyMax);
}
TEST(NanoStringsTest, StrncpyMax) {
ASSERT_GT(::strlen(kLongString), kStrncpyMax);
testStrncpy(kLongString, kStrncpyMax);
}
TEST(NanoStringsTest, StrncpyNothing) {
testStrncpy(kLongString, 0);
}
TEST(NanoStringsTest, StrncpyExactFit) {
ASSERT_EQ(::strlen(kExactString), kStrncpyMax);
testStrncpy(kExactString, kStrncpyMax);
}
static void testHexAscii(uint32_t value, const char *str) {
static constexpr size_t kAsciiLen =
nanoapp_testing::kUint32ToHexAsciiBufferMinLen;
char array[kAsciiLen + 1];
array[kAsciiLen] = kUnsetValue;
uint32ToHexAscii(array, sizeof(array), value);
EXPECT_EQ(kUnsetValue, array[kAsciiLen]);
array[kAsciiLen] = '\0';
EXPECT_STREQ(str, array);
}
TEST(NanoStringsTest, Uint32ToHexAscii) {
testHexAscii(0x1234ABCD, "0x1234ABCD");
}
TEST(NanoStringsTest, Uint32ToHexAsciiMin) {
testHexAscii(0, "0x00000000");
}
TEST(NanoStringsTest, Uint32ToHexAsciiMax) {
testHexAscii(0xFFFFFFFF, "0xFFFFFFFF");
}