compute-runtime/opencl/test/unit_test/program/printf_helper_tests.cpp

923 lines
30 KiB
C++

/*
* Copyright (C) 2018-2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/source/helpers/aligned_memory.h"
#include "shared/source/helpers/string.h"
#include "shared/source/program/print_formatter.h"
#include "shared/test/common/mocks/mock_device.h"
#include "shared/test/common/mocks/mock_graphics_allocation.h"
#include "opencl/test/unit_test/mocks/mock_cl_device.h"
#include "opencl/test/unit_test/mocks/mock_kernel.h"
#include "opencl/test/unit_test/mocks/mock_program.h"
#include "gtest/gtest.h"
#include <cmath>
using namespace NEO;
using namespace iOpenCL;
// -------------------- Base Fixture ------------------------
class PrintFormatterTest : public testing::Test {
public:
std::unique_ptr<PrintFormatter> printFormatter;
static const size_t maxPrintfOutputLength = 4096;
static const size_t printfBufferSize = 1024;
std::string format;
uint8_t buffer;
MockGraphicsAllocation *data;
MockKernel *kernel;
std::unique_ptr<MockProgram> program;
std::unique_ptr<MockKernelInfo> kernelInfo;
ClDevice *device;
uint8_t underlyingBuffer[maxPrintfOutputLength];
uint32_t offset;
int maxStringIndex;
protected:
void SetUp() override {
offset = 4;
maxStringIndex = 0;
data = new MockGraphicsAllocation(underlyingBuffer, maxPrintfOutputLength);
kernelInfo = std::make_unique<MockKernelInfo>();
device = new MockClDevice{MockDevice::createWithNewExecutionEnvironment<MockDevice>(nullptr)};
program = std::make_unique<MockProgram>(toClDeviceVector(*device));
kernel = new MockKernel(program.get(), *kernelInfo, *device);
printFormatter = std::unique_ptr<PrintFormatter>(new PrintFormatter(static_cast<uint8_t *>(data->getUnderlyingBuffer()), printfBufferSize, is32bit, &kernelInfo->kernelDescriptor.kernelMetadata.printfStringsMap));
underlyingBuffer[0] = 0;
underlyingBuffer[1] = 0;
underlyingBuffer[2] = 0;
underlyingBuffer[3] = 0;
}
void TearDown() override {
delete data;
delete kernel;
delete device;
}
enum class PRINTF_DATA_TYPE : int {
INVALID,
BYTE,
SHORT,
INT,
FLOAT,
STRING,
LONG,
POINTER,
DOUBLE,
VECTOR_BYTE,
VECTOR_SHORT,
VECTOR_INT,
VECTOR_LONG,
VECTOR_FLOAT,
VECTOR_DOUBLE
};
PRINTF_DATA_TYPE getPrintfDataType(int8_t value) { return PRINTF_DATA_TYPE::BYTE; };
PRINTF_DATA_TYPE getPrintfDataType(uint8_t value) { return PRINTF_DATA_TYPE::BYTE; };
PRINTF_DATA_TYPE getPrintfDataType(int16_t value) { return PRINTF_DATA_TYPE::SHORT; };
PRINTF_DATA_TYPE getPrintfDataType(uint16_t value) { return PRINTF_DATA_TYPE::SHORT; };
PRINTF_DATA_TYPE getPrintfDataType(int32_t value) { return PRINTF_DATA_TYPE::INT; };
PRINTF_DATA_TYPE getPrintfDataType(uint32_t value) { return PRINTF_DATA_TYPE::INT; };
PRINTF_DATA_TYPE getPrintfDataType(int64_t value) { return PRINTF_DATA_TYPE::LONG; };
PRINTF_DATA_TYPE getPrintfDataType(uint64_t value) { return PRINTF_DATA_TYPE::LONG; };
PRINTF_DATA_TYPE getPrintfDataType(float value) { return PRINTF_DATA_TYPE::FLOAT; };
PRINTF_DATA_TYPE getPrintfDataType(double value) { return PRINTF_DATA_TYPE::DOUBLE; };
PRINTF_DATA_TYPE getPrintfDataType(char *value) { return PRINTF_DATA_TYPE::STRING; };
template <class T>
void injectValue(T value) {
storeData(getPrintfDataType(value));
storeData(value);
}
void injectStringValue(int value) {
storeData(PRINTF_DATA_TYPE::STRING);
storeData(value);
}
template <class T>
void storeData(T value) {
T *valuePointer = reinterpret_cast<T *>(underlyingBuffer + offset);
if (isAligned(valuePointer))
*valuePointer = value;
else {
memcpy_s(valuePointer, sizeof(underlyingBuffer) - offset, &value, sizeof(T));
}
offset += sizeof(T);
// first four bytes always store the size
uint32_t *pointer = reinterpret_cast<uint32_t *>(underlyingBuffer);
*pointer = offset;
}
int injectFormatString(std::string str) {
auto index = maxStringIndex++;
kernelInfo->addToPrintfStringsMap(index, str);
return index;
}
};
// for tests printing a single value
template <class T>
struct SingleValueTestParam {
std::string format;
T value;
};
typedef SingleValueTestParam<int8_t> Int8Params;
typedef SingleValueTestParam<uint8_t> Uint8Params;
typedef SingleValueTestParam<int16_t> Int16Params;
typedef SingleValueTestParam<uint16_t> Uint16Params;
typedef SingleValueTestParam<int32_t> Int32Params;
typedef SingleValueTestParam<uint32_t> Uint32Params;
typedef SingleValueTestParam<int64_t> Int64Params;
typedef SingleValueTestParam<uint64_t> Uint64Params;
typedef SingleValueTestParam<float> FloatParams;
typedef SingleValueTestParam<double> DoubleParams;
typedef SingleValueTestParam<std::string> StringParams;
Int8Params byteValues[] = {
{"%c", 'a'},
};
class PrintfInt8Test : public PrintFormatterTest,
public ::testing::WithParamInterface<Int8Params> {};
TEST_P(PrintfInt8Test, GivenFormatContainingIntWhenPrintingThenValueIsInserted) {
auto input = GetParam();
auto stringIndex = injectFormatString(input.format);
storeData(stringIndex);
injectValue(input.value);
char referenceOutput[maxPrintfOutputLength];
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
snprintf(referenceOutput, sizeof(referenceOutput), input.format.c_str(), input.value);
EXPECT_STREQ(referenceOutput, actualOutput);
}
INSTANTIATE_TEST_CASE_P(PrintfInt8Test,
PrintfInt8Test,
::testing::ValuesIn(byteValues));
Int32Params intValues[] = {
{"%d", 0},
{"%d", 1},
{"%d", -1},
{"%d", INT32_MAX},
{"%d", INT32_MIN},
{"%5d", 10},
{"%-5d", 10},
{"%05d", 10},
{"%+5d", 10},
{"%-+5d", 10},
{"%.5i", 100},
{"%6.5i", 100},
{"%-06i", 100},
{"%06.5i", 100}};
class PrintfInt32Test : public PrintFormatterTest,
public ::testing::WithParamInterface<Int32Params> {};
TEST_P(PrintfInt32Test, GivenFormatContainingIntWhenPrintingThenValueIsInserted) {
auto input = GetParam();
auto stringIndex = injectFormatString(input.format);
storeData(stringIndex);
injectValue(input.value);
char referenceOutput[maxPrintfOutputLength];
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
snprintf(referenceOutput, sizeof(referenceOutput), input.format.c_str(), input.value);
EXPECT_STREQ(referenceOutput, actualOutput);
}
INSTANTIATE_TEST_CASE_P(PrintfInt32Test,
PrintfInt32Test,
::testing::ValuesIn(intValues));
Uint32Params uintValues[] = {
{"%u", 0},
{"%u", 1},
{"%u", UINT32_MAX},
{"%.0u", 0},
// octal
{"%o", 10},
{"%.5o", 10},
{"%#o", 100000000},
{"%04.5o", 10},
// hexadecimal
{"%#x", 0xABCDEF},
{"%#X", 0xABCDEF},
{"%#X", 0},
{"%8x", 399},
{"%04x", 399}};
class PrintfUint32Test : public PrintFormatterTest,
public ::testing::WithParamInterface<Uint32Params> {};
TEST_P(PrintfUint32Test, GivenFormatContainingUintWhenPrintingThenValueIsInserted) {
auto input = GetParam();
auto stringIndex = injectFormatString(input.format);
storeData(stringIndex);
injectValue(input.value);
char referenceOutput[maxPrintfOutputLength];
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
snprintf(referenceOutput, sizeof(referenceOutput), input.format.c_str(), input.value);
EXPECT_STREQ(referenceOutput, actualOutput);
}
TEST_P(PrintfUint32Test, GivenBufferSizeGreaterThanPrintBufferWhenPrintingThenBufferIsTrimmed) {
auto input = GetParam();
printFormatter = std::unique_ptr<PrintFormatter>(new PrintFormatter(static_cast<uint8_t *>(data->getUnderlyingBuffer()), 0, is32bit, &kernelInfo->kernelDescriptor.kernelMetadata.printfStringsMap));
auto stringIndex = injectFormatString(input.format);
storeData(stringIndex);
injectValue(input.value);
char referenceOutput[maxPrintfOutputLength] = "";
char actualOutput[maxPrintfOutputLength] = "";
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ(referenceOutput, actualOutput);
}
INSTANTIATE_TEST_CASE_P(PrintfUint32Test,
PrintfUint32Test,
::testing::ValuesIn(uintValues));
FloatParams floatValues[] = {
{"%f", 10.3456f},
{"%.1f", 10.3456f},
{"%.2f", 10.3456f},
{"%8.3f", 10.3456f},
{"%08.2f", 10.3456f},
{"%-8.2f", 10.3456f},
{"%+8.2f", -10.3456f},
{"%.0f", 0.1f},
{"%.0f", 0.6f},
{"%0f", 0.6f},
};
class PrintfFloatTest : public PrintFormatterTest,
public ::testing::WithParamInterface<FloatParams> {};
TEST_P(PrintfFloatTest, GivenFormatContainingFloatWhenPrintingThenValueIsInserted) {
auto input = GetParam();
auto stringIndex = injectFormatString(input.format);
storeData(stringIndex);
injectValue(input.value);
char referenceOutput[maxPrintfOutputLength];
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
snprintf(referenceOutput, sizeof(referenceOutput), input.format.c_str(), input.value);
EXPECT_STREQ(referenceOutput, actualOutput);
}
INSTANTIATE_TEST_CASE_P(PrintfFloatTest,
PrintfFloatTest,
::testing::ValuesIn(floatValues));
class PrintfDoubleToFloatTest : public PrintFormatterTest,
public ::testing::WithParamInterface<DoubleParams> {};
DoubleParams doubleToFloatValues[] = {
{"%f", 10.3456},
{"%.1f", 10.3456},
{"%.2f", 10.3456},
{"%8.3f", 10.3456},
{"%08.2f", 10.3456},
{"%-8.2f", 10.3456},
{"%+8.2f", -10.3456},
{"%.0f", 0.1},
{"%0f", 0.6},
{"%4g", 12345.6789},
{"%4.2g", 12345.6789},
{"%4G", 0.0000023},
{"%4G", 0.023},
{"%-#20.15e", 19456120.0},
{"%+#21.15E", 19456120.0},
{"%.6a", 0.1},
{"%10.2a", 9990.235}};
TEST_P(PrintfDoubleToFloatTest, GivenFormatContainingFloatAndDoubleWhenPrintingThenValueIsInserted) {
auto input = GetParam();
auto stringIndex = injectFormatString(input.format);
storeData(stringIndex);
injectValue(input.value);
char referenceOutput[maxPrintfOutputLength];
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
snprintf(referenceOutput, sizeof(referenceOutput), input.format.c_str(), input.value);
EXPECT_STREQ(referenceOutput, actualOutput);
}
INSTANTIATE_TEST_CASE_P(PrintfDoubleToFloatTest,
PrintfDoubleToFloatTest,
::testing::ValuesIn(doubleToFloatValues));
DoubleParams doubleValues[] = {
{"%f", 302230.12156260},
{"%+f", 2937289102.1562},
{"% #F", (double)-1254},
{"%6.2f", 0.1562},
{"%06.2f", -0.1562},
{"%e", 0.1562},
{"%E", -1254.0001001},
{"%+.10e", 0.1562000102241},
{"% E", (double)1254},
{"%10.2e", 100230.1562},
{"%g", 74010.00001562},
{"%G", -1254.0001001},
{"%+g", 325001.00001562},
{"%+#G", -1254.0001001},
{"%8.2g", 19.844},
{"%1.5G", -1.1},
{"%.13a", 1890.00001562},
{"%.13A", -1254.0001001},
};
class PrintfDoubleTest : public PrintFormatterTest,
public ::testing::WithParamInterface<DoubleParams> {};
TEST_P(PrintfDoubleTest, GivenFormatContainingDoubleWhenPrintingThenValueIsInserted) {
auto input = GetParam();
auto stringIndex = injectFormatString(input.format);
storeData(stringIndex);
injectValue(input.value);
char referenceOutput[maxPrintfOutputLength];
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
if (input.format[input.format.length() - 1] == 'F')
input.format[input.format.length() - 1] = 'f';
snprintf(referenceOutput, sizeof(referenceOutput), input.format.c_str(), input.value);
EXPECT_STREQ(referenceOutput, actualOutput);
}
INSTANTIATE_TEST_CASE_P(PrintfDoubleTest,
PrintfDoubleTest,
::testing::ValuesIn(doubleValues));
std::pair<std::string, std::string> specialValues[] = {
{"%%", "%"},
{"nothing%", "nothing"},
};
class PrintfSpecialTest : public PrintFormatterTest,
public ::testing::WithParamInterface<std::pair<std::string, std::string>> {};
TEST_P(PrintfSpecialTest, GivenFormatContainingDoublePercentageWhenPrintingThenValueIsInsertedCorrectly) {
auto input = GetParam();
auto stringIndex = injectFormatString(input.first);
storeData(stringIndex);
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ(input.second.c_str(), actualOutput);
}
INSTANTIATE_TEST_CASE_P(PrintfSpecialTest,
PrintfSpecialTest,
::testing::ValuesIn(specialValues));
// ------------------------- Testing Strings only with no Formatting ------------------------
class PrintfNoArgumentsTest : public PrintFormatterTest,
public ::testing::WithParamInterface<std::pair<std::string, std::string>> {};
// escape/non-escaped strings are specified manually to avoid converting them in code
// automatic code would have to do the same thing it is testing and therefore would be prone to mistakes
// this is needed because compiler doesn't escape the format strings and provides them exactly as they were typed in kernel source
std::pair<std::string, std::string> stringValues[] = {
{R"(test)", "test"},
{R"(test\n)", "test\n"},
};
TEST_P(PrintfNoArgumentsTest, GivenNoArgumentsWhenPrintingThenCharsAreEscaped) {
auto input = GetParam();
auto stringIndex = injectFormatString(input.first);
storeData(stringIndex);
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ(input.second.c_str(), actualOutput);
}
INSTANTIATE_TEST_CASE_P(PrintfNoArgumentsTest,
PrintfNoArgumentsTest,
::testing::ValuesIn(stringValues));
StringParams stringValues2[] = {
{"%s", "foo"},
};
class PrintfStringTest : public PrintFormatterTest,
public ::testing::WithParamInterface<StringParams> {};
TEST_P(PrintfStringTest, GivenFormatContainingStringWhenPrintingThenValueIsInserted) {
auto input = GetParam();
auto stringIndex = injectFormatString(input.format);
storeData(stringIndex);
auto inputIndex = injectFormatString(input.value);
injectStringValue(inputIndex);
char referenceOutput[maxPrintfOutputLength];
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
snprintf(referenceOutput, sizeof(referenceOutput), input.format.c_str(), input.value.c_str());
EXPECT_STREQ(input.value.c_str(), actualOutput);
}
INSTANTIATE_TEST_CASE_P(PrintfStringTest,
PrintfStringTest,
::testing::ValuesIn(stringValues2));
TEST_F(PrintFormatterTest, GivenLongStringValueWhenPrintedThenFullStringIsPrinted) {
char testedLongString[maxPrintfOutputLength];
memset(testedLongString, 'a', maxPrintfOutputLength - 1);
testedLongString[maxPrintfOutputLength - 1] = '\0';
auto stringIndex = injectFormatString(testedLongString);
storeData(stringIndex);
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ(testedLongString, actualOutput);
}
TEST_F(PrintFormatterTest, GivenStringSpecifierWhenLongStringIsPassedAsValueThenFullStringIsPrinted) {
char testedLongString[maxPrintfOutputLength];
memset(testedLongString, 'a', maxPrintfOutputLength - 5);
testedLongString[maxPrintfOutputLength - 5] = '\0';
auto stringIndex = injectFormatString("%s");
storeData(stringIndex);
auto inputIndex = injectFormatString(testedLongString);
injectStringValue(inputIndex);
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ(testedLongString, actualOutput);
}
TEST_F(PrintFormatterTest, GivenTooLongStringWhenPrintedThenOutputIsTruncated) {
std::unique_ptr<char[]> testedLongString(new char[PrintFormatter::maxSinglePrintStringLength + 1024]);
memset(testedLongString.get(), 'a', PrintFormatter::maxSinglePrintStringLength + 1024 - 1);
testedLongString[PrintFormatter::maxSinglePrintStringLength + 1024 - 1] = '\0';
auto stringIndex = injectFormatString(testedLongString.get());
storeData(stringIndex);
std::unique_ptr<char[]> actualOutput(new char[PrintFormatter::maxSinglePrintStringLength + 1024]);
printFormatter->printKernelOutput([&actualOutput](char *str) {
size_t length = strnlen_s(str, PrintFormatter::maxSinglePrintStringLength + 1024);
strncpy_s(actualOutput.get(), PrintFormatter::maxSinglePrintStringLength + 1024, str, length); });
auto testedLength = strnlen_s(testedLongString.get(), PrintFormatter::maxSinglePrintStringLength + 1024);
auto actualLength = strnlen_s(actualOutput.get(), PrintFormatter::maxSinglePrintStringLength + 1024);
EXPECT_GT(testedLength, actualLength);
}
TEST_F(PrintFormatterTest, GivenNullTokenWhenPrintingThenNullIsInserted) {
auto stringIndex = injectFormatString("%s");
storeData(stringIndex);
storeData(PRINTF_DATA_TYPE::VECTOR_INT);
storeData(0);
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ("(null)", actualOutput);
}
// ----------------------- Vector channel count ---------------------------------
TEST_F(PrintFormatterTest, GivenVector2WhenPrintingThenAllValuesAreInserted) {
int channelCount = 2;
auto stringIndex = injectFormatString("%v2d");
storeData(stringIndex);
storeData(PRINTF_DATA_TYPE::VECTOR_INT);
// channel count
storeData(channelCount);
// channel values
for (int i = 0; i < channelCount; i++)
storeData(i + 1);
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ("1,2", actualOutput);
}
TEST_F(PrintFormatterTest, GivenVector4WhenPrintingThenAllValuesAreInserted) {
int channelCount = 4;
auto stringIndex = injectFormatString("%v4d");
storeData(stringIndex);
storeData(PRINTF_DATA_TYPE::VECTOR_INT);
// channel count
storeData(channelCount);
// channel values
for (int i = 0; i < channelCount; i++)
storeData(i + 1);
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ("1,2,3,4", actualOutput);
}
TEST_F(PrintFormatterTest, GivenVector8WhenPrintingThenAllValuesAreInserted) {
int channelCount = 8;
auto stringIndex = injectFormatString("%v8d");
storeData(stringIndex);
storeData(PRINTF_DATA_TYPE::VECTOR_INT);
// channel count
storeData(channelCount);
// channel values
for (int i = 0; i < channelCount; i++)
storeData(i + 1);
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ("1,2,3,4,5,6,7,8", actualOutput);
}
TEST_F(PrintFormatterTest, GivenVector16WhenPrintingThenAllValuesAreInserted) {
int channelCount = 16;
auto stringIndex = injectFormatString("%v16d");
storeData(stringIndex);
storeData(PRINTF_DATA_TYPE::VECTOR_INT);
// channel count
storeData(channelCount);
// channel values
for (int i = 0; i < channelCount; i++)
storeData(i + 1);
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ("1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16", actualOutput);
}
// ------------------- vector types ----------------------------
TEST_F(PrintFormatterTest, GivenVectorOfBytesWhenPrintingThenAllValuesAreInserted) {
int channelCount = 2;
auto stringIndex = injectFormatString("%v2hhd");
storeData(stringIndex);
storeData(PRINTF_DATA_TYPE::VECTOR_BYTE);
// channel count
storeData(channelCount);
storeData<int8_t>(1);
storeData<int8_t>(2);
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ("1,2", actualOutput);
}
TEST_F(PrintFormatterTest, GivenVectorOfShortsWhenPrintingThenAllValuesAreInserted) {
int channelCount = 2;
auto stringIndex = injectFormatString("%v2hd");
storeData(stringIndex);
storeData(PRINTF_DATA_TYPE::VECTOR_SHORT);
// channel count
storeData(channelCount);
storeData<int16_t>(1);
storeData<int16_t>(2);
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ("1,2", actualOutput);
}
TEST_F(PrintFormatterTest, GivenVectorOfIntsWhenPrintingThenAllValuesAreInserted) {
int channelCount = 2;
auto stringIndex = injectFormatString("%v2d");
storeData(stringIndex);
storeData(PRINTF_DATA_TYPE::VECTOR_INT);
// channel count
storeData(channelCount);
storeData<int32_t>(1);
storeData<int32_t>(2);
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ("1,2", actualOutput);
}
TEST_F(PrintFormatterTest, GivenSpecialVectorWhenPrintingThenAllValuesAreInserted) {
int channelCount = 2;
auto stringIndex = injectFormatString("%v2hld");
storeData(stringIndex);
storeData(PRINTF_DATA_TYPE::VECTOR_INT);
// channel count
storeData(channelCount);
storeData<int32_t>(1);
storeData<int32_t>(2);
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ("1,2", actualOutput);
}
TEST_F(PrintFormatterTest, GivenVectorOfLongsWhenPrintingThenAllValuesAreInserted) {
int channelCount = 2;
auto stringIndex = injectFormatString("%v2lld");
storeData(stringIndex);
storeData(PRINTF_DATA_TYPE::VECTOR_LONG);
// channel count
storeData(channelCount);
storeData<int64_t>(1);
storeData<int64_t>(2);
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ("1,2", actualOutput);
}
TEST_F(PrintFormatterTest, GivenVectorOfFloatsWhenPrintingThenAllValuesAreInserted) {
int channelCount = 2;
auto stringIndex = injectFormatString("%v2f");
storeData(stringIndex);
storeData(PRINTF_DATA_TYPE::VECTOR_FLOAT);
// channel count
storeData(channelCount);
storeData<float>(1.0);
storeData<float>(2.0);
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ("1.000000,2.000000", actualOutput);
}
TEST_F(PrintFormatterTest, GivenVectorOfDoublesWhenPrintingThenAllValuesAreInserted) {
int channelCount = 2;
auto stringIndex = injectFormatString("%v2f");
storeData(stringIndex);
storeData(PRINTF_DATA_TYPE::VECTOR_DOUBLE);
// channel count
storeData(channelCount);
storeData<double>(1.0);
storeData<double>(2.0);
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ("1.000000,2.000000", actualOutput);
}
TEST_F(PrintFormatterTest, GivenPointerWhenPrintingThenValueIsInserted) {
auto stringIndex = injectFormatString("%p");
storeData(stringIndex);
int temp;
storeData(PRINTF_DATA_TYPE::POINTER);
// channel count
storeData(reinterpret_cast<void *>(&temp));
// on 32bit configurations add extra 4 bytes when storing pointers, IGC always stores pointers on 8 bytes
if (is32bit) {
uint32_t padding = 0;
storeData(padding);
}
char actualOutput[maxPrintfOutputLength];
char referenceOutput[maxPrintfOutputLength];
snprintf(referenceOutput, sizeof(referenceOutput), "%p", reinterpret_cast<void *>(&temp));
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ(referenceOutput, actualOutput);
}
TEST_F(PrintFormatterTest, GivenPointerWith32BitKernelWhenPrintingThen32BitPointerIsPrinted) {
printFormatter.reset(new PrintFormatter(static_cast<uint8_t *>(data->getUnderlyingBuffer()), printfBufferSize, true, &kernelInfo->kernelDescriptor.kernelMetadata.printfStringsMap));
auto stringIndex = injectFormatString("%p");
storeData(stringIndex);
kernelInfo->kernelDescriptor.kernelAttributes.gpuPointerSize = 4;
storeData(PRINTF_DATA_TYPE::POINTER);
// store pointer
uint32_t addressValue = 0;
storeData(addressValue);
void *pointer = nullptr;
// store non zero padding
uint32_t padding = 0xdeadbeef;
storeData(padding);
char actualOutput[maxPrintfOutputLength];
char referenceOutput[maxPrintfOutputLength];
snprintf(referenceOutput, sizeof(referenceOutput), "%p", pointer);
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ(referenceOutput, actualOutput);
}
TEST_F(PrintFormatterTest, Given2ByteVectorsWhenPrintingThenDataBufferParsedProperly) {
int channelCount = 4;
auto stringIndex = injectFormatString("%v4hhd %v4hhd");
storeData(stringIndex);
storeData(PRINTF_DATA_TYPE::VECTOR_BYTE);
// channel count
storeData(channelCount);
// channel values
for (int i = 0; i < channelCount; i++)
storeData(static_cast<int8_t>(i + 1));
// filler, should not be printed
for (int i = 0; i < 12; i++)
storeData(static_cast<int8_t>(0));
storeData(PRINTF_DATA_TYPE::VECTOR_BYTE);
// channel count
storeData(channelCount);
// channel values
for (int i = 0; i < channelCount; i++)
storeData(static_cast<int8_t>(i + 1));
// filler, should not be printed
for (int i = 0; i < 12; i++)
storeData(static_cast<int8_t>(0));
char actualOutput[maxPrintfOutputLength];
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ("1,2,3,4 1,2,3,4", actualOutput);
}
TEST_F(PrintFormatterTest, GivenEmptyBufferWhenPrintingThenFailSafely) {
char actualOutput[maxPrintfOutputLength];
actualOutput[0] = 0;
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ("", actualOutput);
}
TEST_F(PrintFormatterTest, GivenNoStringMapAndBufferWithFormatStringThenItIsPrintedProperly) {
printFormatter.reset(new PrintFormatter(static_cast<uint8_t *>(data->getUnderlyingBuffer()), printfBufferSize, true));
const char *formatString = "test string";
storeData(formatString);
char output[maxPrintfOutputLength];
printFormatter->printKernelOutput([&output](char *str) { strncpy_s(output, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ(formatString, output);
}
TEST_F(PrintFormatterTest, GivenNoStringMapAndBufferWithFormatStringAnd2StringsThenDataIsParsedAndPrintedProperly) {
printFormatter.reset(new PrintFormatter(static_cast<uint8_t *>(data->getUnderlyingBuffer()), printfBufferSize, true));
const char *formatString = "%s %s";
storeData(formatString);
const char *string1 = "str1";
storeData(PRINTF_DATA_TYPE::STRING);
storeData(string1);
const char *string2 = "str2";
storeData(PRINTF_DATA_TYPE::STRING);
storeData(string2);
const char *expectedOutput = "str1 str2";
char output[maxPrintfOutputLength];
printFormatter->printKernelOutput([&output](char *str) { strncpy_s(output, maxPrintfOutputLength, str, maxPrintfOutputLength); });
EXPECT_STREQ(expectedOutput, output);
}
TEST(printToSTDOUTTest, GivenStringWhenPrintingToStdoutThenOutputOccurs) {
testing::internal::CaptureStdout();
printToSTDOUT("test");
std::string output = testing::internal::GetCapturedStdout();
EXPECT_STREQ("test", output.c_str());
}
TEST(simpleSprintf, GivenEmptyFormatStringWhenSimpleSprintfIsCalledThenBailOutWith0) {
char out[1024] = {7, 0};
auto ret = simple_sprintf<float>(out, sizeof(out), "", 3.0f);
EXPECT_EQ(0U, ret);
EXPECT_EQ(0, out[0]);
EXPECT_EQ(0, out[1]);
}