Implementation of OICStrcat/OICStrcpy
authorErich Keane <erich.keane@intel.com>
Thu, 21 May 2015 22:47:24 +0000 (15:47 -0700)
committerErich Keane <erich.keane@intel.com>
Fri, 29 May 2015 15:55:11 +0000 (15:55 +0000)
Repeated mistakes based on copy and cat operations in the C
code shows that we need a unified implementation that is as safe as
possible.  These implementations closely emulate the Microsoft _S
versions of these functions, which seem to be safest feature wise.

Replacing copy and cat operations is reserved for a different
commit.

Change-Id: Id1f6f4515a00679661cc722419fa0bab84a624c2
Signed-off-by: Erich Keane <erich.keane@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/1115
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: John Light <john.j.light@intel.com>
resource/csdk/connectivity/common/inc/oic_string.h
resource/csdk/connectivity/common/src/oic_string.c
resource/csdk/connectivity/test/SConscript
resource/csdk/connectivity/test/oic_string_tests.cpp [new file with mode: 0644]

index 5c823ba084adca45c20f0598f26fab05082e142d..9f3ca2e94d90f36b43e68f0340931d9fd99efb4f 100644 (file)
@@ -20,6 +20,7 @@
 #ifndef OIC_STRING_H_
 #define OIC_STRING_H_
 
+#include <stddef.h>
 #ifdef __cplusplus
 extern "C"
 {
@@ -28,17 +29,69 @@ extern "C"
 /**
  * Duplicates the source string and returns it.
  *
- * NOTE: Caller needs to clear this memory by calling OICFree.
+ * @note Caller needs to release this memory by calling @ref OICFree.
  *
- * @param str - Original valid string which needs to be duplicated
+ * @param str Original valid string which needs to be duplicated.
  *
- * @return
- *     on success, a pointer to the duplicated string
- *     on failure, a null pointer is returned
+ * @return a pointer to the duplicated string
  */
 char *OICStrdup(const char *str);
 
+/**
+ * Copies a C string into destination buffer.  Ensures that the destination
+ * is null terminated.
+ *
+ * @param dest Destination C buffer.
+ * @param destSize The allocated size of the destination parameter.
+ * @param source Source C string.
+ *
+ * @return
+ *      returns a pointer to the passed in 'dest' parameter
+ */
+char* OICStrcpy(char* dest, size_t destSize, const char* source);
+
+/**
+ * Appends a C string into a previously allocated and initialized C string in a buffer. dest
+ * parameter is guaranteed to be null-terminated.
+ *
+ * @param dest Destination C buffer containing initial string.
+ * @param destSize The allocated size of the destination parameter.
+ * @param source Source C string.
+ *
+ * @return
+ *      returns a pointer to the passed in 'dest' parameter
+ */
+char* OICStrcat(char* dest, size_t destSize, const char* source);
+
+/**
+ * Copies a partial C string into destination buffer.
+ * Ensures that the destination is null terminated.
+ *
+ * @param dest Destination C buffer.
+ * @param destSize The allocated size of the destination parameter.
+ * @param source Source C string.
+ * @param sourceLen maximum number of characters to copy.
+ *
+ * @return
+ *      returns a pointer to the passed in 'dest' parameter
+ */
+char* OICStrcpyPartial(char* dest, size_t destSize, const char* source, size_t sourceLen);
+
+/**
+ * Appends a C string into a previously allocated and initialized C string in a buffer. dest
+ * parameter is guaranteed to be null-terminated.
+ *
+ * @param dest Destination C buffer containing initial string.
+ * @param destSize The allocated size of the destination parameter.
+ * @param source Source C string.
+ * @param sourceLen maximum number of characters to append, not including null termination
+ *
+ * @return
+ *      returns a pointer to the passed in 'dest' parameter
+ */
+char* OICStrcatPartial(char* dest, size_t destSize, const char* source, size_t sourceLen);
+
 #ifdef __cplusplus
 }
 #endif // __cplusplus
-#endif /* OIC_STRING_H_ */
+#endif // OIC_STRING_H_
index 199b6f6bf44da77a54d53fb55b22cfc4a72d7abb..ec787d4d34604e246c8aa22fde37e10dd0ed0584 100644 (file)
 #include "oic_string.h"
 
 #include <string.h>
+#include <assert.h>
+#include "logger.h"
 #include "oic_malloc.h"
 
+#define TAG "OIC_STRING"
 char *OICStrdup(const char *str)
 {
+    assert(str);
+
     // Allocate memory for original string length and 1 extra byte for '\0'
     size_t length = strlen(str);
     char *dup = (char *)OICMalloc(length + 1);
@@ -31,6 +36,65 @@ char *OICStrdup(const char *str)
     {
         memcpy(dup, str, length + 1);
     }
+    else
+    {
+        assert(NULL != dup);
+    }
+
     return dup;
 }
 
+char* OICStrcpy(char* dest, size_t destSize, const char* source)
+{
+    return OICStrcpyPartial(dest, destSize, source, destSize);
+}
+
+char* OICStrcat(char* dest, size_t destSize, const char* source)
+{
+    return OICStrcatPartial(dest, destSize, source, destSize);
+}
+
+static size_t min3(size_t a, size_t b, size_t c)
+{
+    return a < b ? (a < c ? a : c) : (b < c ? b: c);
+}
+
+char* OICStrcpyPartial(char* dest, size_t destSize, const char* source, size_t sourceLen)
+{
+    assert(dest);
+    assert(source);
+
+    if(destSize == 0 || sourceLen == 0)
+    {
+        return dest;
+    }
+
+    size_t limit = min3(destSize - 1, sourceLen, strlen(source));
+    memcpy(dest, source, limit);
+    dest[limit] = '\0';
+
+    return dest;
+}
+
+char* OICStrcatPartial(char* dest, size_t destSize, const char* source, size_t sourceLen)
+{
+    assert(dest);
+    assert(source);
+
+    if(destSize == 0 || sourceLen == 0)
+    {
+        return dest;
+    }
+
+    size_t destLen = strlen(dest);
+
+    if (destLen >= destSize)
+    {
+        return dest;
+    }
+
+    size_t limit = min3(destSize - destLen - 1, sourceLen, strlen(source));
+    memcpy(dest + destLen, source, limit);
+    dest[destLen + limit] = '\0';
+    return dest;
+}
index 7189319b9c3ce2d1c07031747743b49d369f2dcb..ca464db0b4955d9433aa77899cc925f457eec814 100644 (file)
@@ -74,7 +74,8 @@ if env.get('LOGGING'):
 catests = catest_env.Program('catests', ['catests.cpp',
                                          'caprotocolmessagetest.cpp',
                                                'ca_api_unittest.cpp',
-                                               'camutex_tests.cpp'])
+                                               'camutex_tests.cpp',
+                                               'oic_string_tests.cpp'])
 
 Alias("test", [catests])
 
diff --git a/resource/csdk/connectivity/test/oic_string_tests.cpp b/resource/csdk/connectivity/test/oic_string_tests.cpp
new file mode 100644 (file)
index 0000000..93eb731
--- /dev/null
@@ -0,0 +1,538 @@
+//******************************************************************
+//
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// 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.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+//
+//*********************************************************************
+
+// Defining _POSIX_C_SOURCE macro with 200809L (or greater) as value
+// causes header files to expose definitions
+// corresponding to the POSIX.1-2008 base
+// specification (excluding the XSI extension).
+// For POSIX.1-2008 base specification,
+// Refer http://pubs.opengroup.org/stage7tc1/
+//
+// For this specific file, see use of usleep
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200809L
+#endif // _POSIX_C_SOURCE
+
+#include "gtest/gtest.h"
+
+#include <oic_string.h>
+
+const char SENTINEL_VALUE = 127;
+TEST(StringTests, StrdupNormalDup)
+{
+    char param[] = "This is a normal parameter";
+
+    char* result = OICStrdup(param);
+
+    ASSERT_TRUE(result != NULL);
+
+    // ensure not the same pointer
+    EXPECT_NE(param, result);
+
+    EXPECT_STREQ(param, result);
+}
+
+// Tests a normal copy where the buffer is exactly long enough
+TEST(StringTests, StrcpyExactSize)
+{
+    char target[10];
+    memset(target, SENTINEL_VALUE, sizeof(target));
+    char source[] = "123456789";
+
+    char* result = OICStrcpy(target, sizeof(target), source);
+
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof(target) - 1, strlen(target));
+    EXPECT_STREQ(source, result);
+}
+
+// Tests a normal copy where the buffer is exactly long enough
+// Tests with what is in reality an oversized buffer to ensure that
+// the buffer isn't over-written
+TEST(StringTests, StrcpyExactSizeSentinel)
+{
+    char target[10 + 5];
+    memset(target, SENTINEL_VALUE, sizeof(target));
+    char source[] = "123456789";
+
+    char* result = OICStrcpy(target, sizeof(target) - 5, source);
+
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof(target) - 1 - 5, strlen(target));
+    EXPECT_STREQ(source, result);
+
+    for(size_t i = sizeof(target) - 5; i < sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}
+
+// tests a copy where the source is smaller than the target
+TEST(StringTests, StrcpyShorterSource)
+{
+    char target[10];
+    memset(target, SENTINEL_VALUE, sizeof(target));
+    char source[] = "12345";
+
+    char* result = OICStrcpy(target, sizeof(target), source);
+
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof(source) - 1, strlen(result));
+    EXPECT_STREQ(source, result);
+
+    for(size_t i = sizeof(source); i < sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}
+
+// tests a copy where the destination is larger than the target
+TEST(StringTests, StrcpyShorterDestination)
+{
+    char target[10];
+    memset(target, SENTINEL_VALUE, sizeof(target));
+    char source[] = "123456789012345";
+
+    char *result = OICStrcpy(target, sizeof(target), source);
+
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof(target) - 1, strlen(result));
+    EXPECT_STREQ("123456789", result);
+}
+
+// tests a copy where the destination is larger than the target
+// Tests with what is in reality an oversized buffer to ensure that
+// the buffer isn't over-written
+TEST(StringTests, StrcpyShorterDestinationSentinel)
+{
+    char target[10 + 5];
+    memset(target, SENTINEL_VALUE, sizeof(target));
+    char source[] = "123456789012345";
+
+    char *result = OICStrcpy(target, sizeof(target) - 5, source);
+
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof(target) - 1 - 5, strlen(result));
+    EXPECT_STREQ("123456789", result);
+
+    for(size_t i = sizeof(target) - 5; i < sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}
+
+// tests a copy where the source is of length 0
+TEST(StringTests, StrcpyZeroSource)
+{
+    char target[10];
+    memset(target, SENTINEL_VALUE, sizeof(target));
+    char source[] = "";
+
+    char *result = OICStrcpy(target, sizeof(target), source);
+
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof(source) - 1, strlen(result));
+    EXPECT_STREQ("", result);
+
+    for(size_t i = sizeof(source); i < sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}
+
+// tests a copy where the destination is of length 0
+TEST(StringTests, StrcpyZeroDestination)
+{
+    char target[0];
+    char source[] = "123456789";
+
+    char *result = OICStrcpy(target, sizeof(target), source);
+
+    EXPECT_EQ(target, result);
+}
+
+// tests a copy where the destination is of length 0
+// Tests with what is in reality an oversized buffer to ensure that
+// the buffer isn't over-written
+TEST(StringTests, StrcpyZeroDestinationSentinel)
+{
+    char target[0 + 5];
+    memset(target, SENTINEL_VALUE, sizeof(target));
+    char source[] = "123456789";
+
+    char *result = OICStrcpy(target, sizeof(target) - 5, source);
+
+    EXPECT_EQ(target, result);
+
+    for(size_t i = 0; i < sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}
+
+// Tests a normal cat where the target has exactly enough room
+TEST(StringTests, StrcatExactSize)
+{
+    char target[10] = "Orig";
+    memset(target + sizeof("Orig"), SENTINEL_VALUE, sizeof(target) - sizeof("Orig"));
+    char source[] = "12345";
+
+    char *result = OICStrcat(target, sizeof(target), source);
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof(target) - 1, strlen(target));
+    EXPECT_STREQ("Orig12345", target);
+}
+
+// Tests a normal cat where the target has exactly enough room
+// Tests with what is in reality an oversized buffer to ensure that
+// the buffer isn't over-written
+TEST(StringTests, StrcatExactSizeSentinel)
+{
+    char target[10 + 5] = "Orig";
+    memset(target + sizeof("Orig"), SENTINEL_VALUE, sizeof(target) - sizeof("Orig"));
+    char source[] = "12345";
+
+    char *result = OICStrcat(target, sizeof(target) - 5, source);
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof(target) - 1 - 5, strlen(target));
+    EXPECT_STREQ("Orig12345", target);
+
+    for(size_t i = sizeof(target) - 5; i < sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}
+
+// tests a normal cat where the target has exactly enough room,
+// except it is of strlen 0
+TEST(StringTests, StrcatExactSizeEmptySourceString)
+{
+    char target[10];
+    memset(target, SENTINEL_VALUE, sizeof(target));
+    target[0] = '\0';
+    char source[] = "123456789";
+
+    char *result = OICStrcat(target, sizeof(target), source);
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof(target) - 1, strlen(target));
+    EXPECT_STREQ(source, target);
+}
+// tests a normal cat where the target has exactly enough room,
+// except it is of strlen 0
+// Tests with what is in reality an oversized buffer to ensure that
+// the buffer isn't over-written
+TEST(StringTests, StrcatExactSizeEmptySourceStringSentinel)
+{
+    char target[10 + 5];
+    memset(target, SENTINEL_VALUE, sizeof(target));
+    target[0] = '\0';
+    char source[] = "123456789";
+
+    char *result = OICStrcat(target, sizeof(target) + 5, source);
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof(target) - 1 - 5, strlen(target));
+    EXPECT_STREQ(source, target);
+
+    for(size_t i = sizeof(target) - 5; i < sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}
+
+// tests a normal cat where the target has extra room
+TEST(StringTests, StrcatExtraRoom)
+{
+    char target[10] = "Orig";
+    memset(target + sizeof("Orig"), SENTINEL_VALUE, sizeof(target) - sizeof("Orig"));
+    char source[] = "12";
+
+    char *result = OICStrcat(target, sizeof(target), source);
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(6, strlen(target));
+    EXPECT_STREQ("Orig12", target);
+
+    for(size_t i = sizeof("Orig12"); i < sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}
+
+// Tests a normal cat where the target has insufficient room
+TEST(StringTests, StrcatInsufficientRoom)
+{
+    char target[10];
+    memset(target, SENTINEL_VALUE, sizeof(target));
+    target[0] = '\0';
+    char source[] = "1234567890123456";
+
+    char *result = OICStrcat(target, sizeof(target), source);
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof(target) - 1, strlen(target));
+    EXPECT_STREQ("123456789", target);
+}
+
+// Tests a normal cat where the target has insufficient room
+// Tests with what is in reality an oversized buffer to ensure that
+// the buffer isn't over-written
+TEST(StringTests, StrcatInsufficientRoomSentinel)
+{
+    char target[10 + 5];
+    memset(target, SENTINEL_VALUE, sizeof(target));
+    target[0]= '\0';
+    char source[] = "1234567890123456";
+
+    char *result = OICStrcat(target, sizeof(target) - 5, source);
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof(target) - 1 - 5, strlen(target));
+    EXPECT_STREQ("123456789", target);
+
+    for(size_t i = sizeof(target) - 5; i < sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}
+
+// Tests a normal cat where the target has zero room
+TEST(StringTests, StrcatZeroRoom)
+{
+    char target[10] = "Original1";
+    char source[] = "12345";
+
+    char *result = OICStrcat(target, sizeof(target), source);
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof(target) - 1, strlen(target));
+    EXPECT_STREQ("Original1", target);
+}
+
+// Tests a normal cat where the target has zero room
+// Tests with what is in reality an oversized buffer to ensure that
+// the buffer isn't over-written
+TEST(StringTests, StrcatZeroRoomSentinel)
+{
+    char target[10 + 5] = "Original1";
+    memset(target + sizeof("Original1"), SENTINEL_VALUE, sizeof(target) - sizeof("Original1"));
+    char source[] = "12345";
+
+    char *result = OICStrcat(target, sizeof(target) - 5, source);
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof(target) - 1 - 5, strlen(target));
+    EXPECT_STREQ("Original1", target);
+
+    for(size_t i = sizeof(target) - 5; i < sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}
+
+// Tests a cat where the source is zero length
+TEST(StringTests, StrcatZeroSource)
+{
+    char target[10] = "Orig";
+    memset(target + sizeof("Orig"), SENTINEL_VALUE, sizeof(target) - sizeof("Orig"));
+    char source[] = "";
+
+    char *result = OICStrcat(target, sizeof(target), source);
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof("Orig") - 1, strlen(target));
+    EXPECT_STREQ("Orig", target);
+
+    for(size_t i = sizeof("Orig"); i < sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}
+
+// Tests a cat where the Destination is zero length
+TEST(StringTests, StrcatZeroDestination)
+{
+    char target[0];
+    char source[] = "12345";
+
+    char *result = OICStrcat(target, sizeof(target), source);
+    EXPECT_EQ(target, result);
+}
+
+// Tests a cat where the Destination is zero length
+// Tests with what is in reality an oversized buffer to ensure that
+// the buffer isn't over-written
+TEST(StringTests, StrcatZeroDestinationSentinel)
+{
+    char target[0 + 5];
+    memset(target, SENTINEL_VALUE, sizeof(target));
+    char source[] = "123456789";
+
+    char *result = OICStrcat(target, sizeof(target) - 5, source);
+
+    EXPECT_EQ(target, result);
+
+    for(size_t i = 0; i < sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}
+
+// Tests a partial copy where the source length parameter is shorter
+// than the string length
+TEST(StringTests, StrcpyPartialShorterSourceLen)
+{
+    char target[10];
+    memset(target, SENTINEL_VALUE, sizeof(target));
+    char source[] = "123456789";
+
+    char* result = OICStrcpyPartial(target, sizeof(target), source, strlen(source) - 5);
+
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(strlen(source) - 5, strlen(target));
+    EXPECT_STREQ("1234", result);
+
+    for(size_t i = strlen(target) + 1; i< sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}
+
+// Tests a partial copy where the source length parameter is equal
+// to the string length
+TEST(StringTests, StrcpyPartialEqualSourceLen)
+{
+    char target[10];
+    memset(target, SENTINEL_VALUE, sizeof(target));
+    char source[] = "123456789";
+
+    char* result = OICStrcpyPartial(target, sizeof(target), source, strlen(source));
+
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof(target) - 1, strlen(target));
+    EXPECT_STREQ(source, result);
+}
+
+// Tests a partial copy where the source length parameter is longer
+// than the string length
+TEST(StringTests, StrcpyPartialLongerSourceLen)
+{
+    char target[10];
+    memset(target, SENTINEL_VALUE, sizeof(target));
+    char source[] = "123456789";
+
+    char* result = OICStrcpyPartial(target, sizeof(target), source, 99);
+
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof(target) - 1, strlen(target));
+    EXPECT_STREQ(source, result);
+}
+
+// Tests a partial copy where the source length is zero
+TEST(StringTests, StrcpyPartialZeroSourceLen)
+{
+    char target[10];
+    memset(target, SENTINEL_VALUE, sizeof(target));
+    char source[] = "123456789";
+
+    char* result = OICStrcpyPartial(target, sizeof(target), source, 0);
+
+    EXPECT_EQ(target, result);
+
+    for(size_t i = 0; i < sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, target[i]);
+    }
+}
+
+// Tests a partial cat where the source length parameter is shorter
+// than the string length
+TEST(StringTests, StrcatPartialShorterSourceLen)
+{
+    char target[10] = "Orig";
+    memset(target + sizeof("Orig"), SENTINEL_VALUE, sizeof(target) + sizeof("Orig"));
+    char source[] = "123456";
+
+    char* result = OICStrcatPartial(target, sizeof(target), source, strlen(source) - 3);
+
+    EXPECT_EQ(target, result);
+    EXPECT_EQ((sizeof("Orig") - 1) + (strlen(source) - 3), strlen(target));
+    EXPECT_STREQ("Orig123", result);
+
+    for(size_t i = strlen(target) + 1; i< sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}
+
+// Tests a partial cat where the source length parameter is equal
+// to the string length
+TEST(StringTests, StrcatPartialEqualSourceLen)
+{
+    char target[10] = "Orig";
+    memset(target + sizeof("Orig"), SENTINEL_VALUE, sizeof(target) + sizeof("Orig"));
+    char source[] = "123";
+
+    char* result = OICStrcatPartial(target, sizeof(target), source, strlen(source));
+
+    EXPECT_EQ(target, result);
+    EXPECT_EQ((sizeof("Orig") - 1) + strlen(source), strlen(target));
+    EXPECT_STREQ("Orig123", result);
+
+    for(size_t i = strlen(target) + 1; i< sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}
+
+// Tests a partial cat where the source length parameter is longer
+// than the string length
+TEST(StringTests, StrcatPartialLongerSourceLen)
+{
+    char target[10] = "Orig";
+    memset(target + sizeof("Orig"), SENTINEL_VALUE, sizeof(target) + sizeof("Orig"));
+    char source[] = "123";
+
+    char* result = OICStrcatPartial(target, sizeof(target), source, 99);
+
+    EXPECT_EQ(target, result);
+    EXPECT_EQ((sizeof("Orig") - 1) + strlen(source), strlen(target));
+    EXPECT_STREQ("Orig123", result);
+
+    for(size_t i = strlen(target) + 1; i< sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}
+
+// Tests a partial cat where the source length is zero
+TEST(StringTests, StrcatPartialZeroSourceLen)
+{
+    char target[10] = "Orig";
+    memset(target + sizeof("Orig"), SENTINEL_VALUE, sizeof(target) + sizeof("Orig"));
+    char source[] = "123";
+
+    char* result = OICStrcatPartial(target, sizeof(target), source, 0);
+
+    EXPECT_EQ(target, result);
+    EXPECT_EQ(sizeof("Orig") - 1, strlen(target));
+    EXPECT_STREQ("Orig", result);
+
+    for(size_t i = strlen(target) + 1; i< sizeof(target); ++i)
+    {
+        EXPECT_EQ(SENTINEL_VALUE, result[i]);
+    }
+}