844 lines
28 KiB
C++
844 lines
28 KiB
C++
/*
|
|
* Copyright (c) 2017 - 2018, Intel Corporation
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include "runtime/helpers/aligned_memory.h"
|
|
#include "runtime/helpers/string.h"
|
|
#include "runtime/program/print_formatter.h"
|
|
#include "unit_tests/mocks/mock_kernel.h"
|
|
#include "unit_tests/mocks/mock_program.h"
|
|
#include "unit_tests/mocks/mock_graphics_allocation.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <cmath>
|
|
|
|
using namespace OCLRT;
|
|
using namespace iOpenCL;
|
|
|
|
// -------------------- Base Fixture ------------------------
|
|
class PrintFormatterTest : public testing::Test {
|
|
public:
|
|
PrintFormatter *printFormatter;
|
|
|
|
std::string format;
|
|
uint8_t buffer;
|
|
|
|
MockGraphicsAllocation *data;
|
|
MockKernel *kernel;
|
|
MockProgram program;
|
|
KernelInfo *kernelInfo;
|
|
Device *device;
|
|
|
|
uint8_t underlyingBuffer[PrintFormatter::maxPrintfOutputLength];
|
|
uint32_t offset;
|
|
|
|
int maxStringIndex;
|
|
|
|
protected:
|
|
void SetUp() override {
|
|
offset = 4;
|
|
maxStringIndex = 0;
|
|
data = new MockGraphicsAllocation(underlyingBuffer, PrintFormatter::maxPrintfOutputLength);
|
|
|
|
kernelInfo = KernelInfo::create();
|
|
device = Device::create<OCLRT::Device>(nullptr, false);
|
|
kernel = new MockKernel(&program, *kernelInfo, *device);
|
|
|
|
printFormatter = new PrintFormatter(*kernel, *data);
|
|
|
|
underlyingBuffer[0] = 0;
|
|
underlyingBuffer[1] = 0;
|
|
underlyingBuffer[2] = 0;
|
|
underlyingBuffer[3] = 0;
|
|
}
|
|
|
|
void TearDown() override {
|
|
delete printFormatter;
|
|
delete data;
|
|
delete kernel;
|
|
delete kernelInfo;
|
|
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) {
|
|
size_t strSize = str.length() + 1;
|
|
|
|
SPatchString printfString;
|
|
printfString.Token = PATCH_TOKEN_STRING;
|
|
printfString.Size = static_cast<uint32_t>(sizeof(SPatchString) + strSize);
|
|
|
|
printfString.Index = maxStringIndex++;
|
|
printfString.StringSize = static_cast<uint32_t>(strSize);
|
|
|
|
cl_char *pPrintfString = new cl_char[printfString.Size];
|
|
memcpy_s(pPrintfString, sizeof(SPatchString), &printfString, sizeof(SPatchString));
|
|
memcpy_s((cl_char *)pPrintfString + sizeof(printfString), strSize, str.c_str(), strSize);
|
|
|
|
kernelInfo->storePatchToken(reinterpret_cast<SPatchString *>(pPrintfString));
|
|
|
|
delete[] pPrintfString;
|
|
return printfString.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, GivenPrintfFormatWhenConatinsIntThenInstertValueIntoString) {
|
|
auto input = GetParam();
|
|
|
|
auto stringIndex = injectFormatString(input.format);
|
|
storeData(stringIndex);
|
|
injectValue(input.value);
|
|
|
|
char referenceOutput[PrintFormatter::maxPrintfOutputLength];
|
|
char actualOutput[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::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, GivenPrintfFormatWhenConatinsIntThenInstertValueIntoString) {
|
|
auto input = GetParam();
|
|
|
|
auto stringIndex = injectFormatString(input.format);
|
|
storeData(stringIndex);
|
|
injectValue(input.value);
|
|
|
|
char referenceOutput[PrintFormatter::maxPrintfOutputLength];
|
|
char actualOutput[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::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, GivenPrintfFormatWhenConatinsUintThenInstertValueIntoString) {
|
|
auto input = GetParam();
|
|
|
|
auto stringIndex = injectFormatString(input.format);
|
|
storeData(stringIndex);
|
|
injectValue(input.value);
|
|
|
|
char referenceOutput[PrintFormatter::maxPrintfOutputLength];
|
|
char actualOutput[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::maxPrintfOutputLength); });
|
|
|
|
snprintf(referenceOutput, sizeof(referenceOutput), input.format.c_str(), input.value);
|
|
|
|
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, GivenPrintfFormatWhenConatinsFloatThenInstertValueIntoString) {
|
|
auto input = GetParam();
|
|
|
|
auto stringIndex = injectFormatString(input.format);
|
|
storeData(stringIndex);
|
|
injectValue(input.value);
|
|
|
|
char referenceOutput[PrintFormatter::maxPrintfOutputLength];
|
|
char actualOutput[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::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.6},
|
|
{"%.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, GivenPrintfFormatWhenConatinsFloatFormatAndDoubleValueThenInstertValueIntoString) {
|
|
auto input = GetParam();
|
|
|
|
auto stringIndex = injectFormatString(input.format);
|
|
storeData(stringIndex);
|
|
injectValue(input.value);
|
|
|
|
char referenceOutput[PrintFormatter::maxPrintfOutputLength];
|
|
char actualOutput[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::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, GivenPrintfFormatWhenConatinsDoubleThenInstertValueIntoString) {
|
|
auto input = GetParam();
|
|
|
|
auto stringIndex = injectFormatString(input.format);
|
|
storeData(stringIndex);
|
|
injectValue(input.value);
|
|
|
|
char referenceOutput[PrintFormatter::maxPrintfOutputLength];
|
|
char actualOutput[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::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, DoublePercentageIntoOne) {
|
|
auto input = GetParam();
|
|
|
|
auto stringIndex = injectFormatString(input.first);
|
|
storeData(stringIndex);
|
|
|
|
char actualOutput[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::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, GivenPrintfFormatWhenNoArgumentsThenEscapeChars) {
|
|
auto input = GetParam();
|
|
|
|
auto stringIndex = injectFormatString(input.first);
|
|
storeData(stringIndex);
|
|
|
|
char actualOutput[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::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, GivenPrintfFormatWhenStringArgumentThenInsertValue) {
|
|
auto input = GetParam();
|
|
|
|
auto stringIndex = injectFormatString(input.format);
|
|
storeData(stringIndex);
|
|
|
|
auto inputIndex = injectFormatString(input.value);
|
|
injectStringValue(inputIndex);
|
|
|
|
char referenceOutput[PrintFormatter::maxPrintfOutputLength];
|
|
char actualOutput[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::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, GivenPrintfFormatWhenStringArgumentButNullTokenThenPrintNull) {
|
|
auto stringIndex = injectFormatString("%s");
|
|
storeData(stringIndex);
|
|
|
|
storeData(PRINTF_DATA_TYPE::VECTOR_INT);
|
|
storeData(0);
|
|
|
|
char actualOutput[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::maxPrintfOutputLength); });
|
|
|
|
EXPECT_STREQ("(null)", actualOutput);
|
|
}
|
|
|
|
// ----------------------- Vector channel count ---------------------------------
|
|
TEST_F(PrintFormatterTest, GivenPrintfFormatWhenVector2ThenInsertAllValues) {
|
|
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[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::maxPrintfOutputLength); });
|
|
|
|
EXPECT_STREQ("1,2", actualOutput);
|
|
}
|
|
|
|
TEST_F(PrintFormatterTest, GivenPrintfFormatWhenVector4ThenInsertAllValues) {
|
|
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[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::maxPrintfOutputLength); });
|
|
|
|
EXPECT_STREQ("1,2,3,4", actualOutput);
|
|
}
|
|
|
|
TEST_F(PrintFormatterTest, GivenPrintfFormatWhenVector8ThenInsertAllValues) {
|
|
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[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::maxPrintfOutputLength); });
|
|
|
|
EXPECT_STREQ("1,2,3,4,5,6,7,8", actualOutput);
|
|
}
|
|
|
|
TEST_F(PrintFormatterTest, GivenPrintfFormatWhenVector16ThenInsertAllValues) {
|
|
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[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::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, GivenPrintfFormatWhenVectorOfBytesThenInsertAllValues) {
|
|
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[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::maxPrintfOutputLength); });
|
|
|
|
EXPECT_STREQ("1,2", actualOutput);
|
|
}
|
|
|
|
TEST_F(PrintFormatterTest, GivenPrintfFormatWhenVectorOfShortsThenInsertAllValues) {
|
|
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[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::maxPrintfOutputLength); });
|
|
|
|
EXPECT_STREQ("1,2", actualOutput);
|
|
}
|
|
|
|
TEST_F(PrintFormatterTest, GivenPrintfFormatWhenVectorOfIntsThenInsertAllValues) {
|
|
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[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::maxPrintfOutputLength); });
|
|
|
|
EXPECT_STREQ("1,2", actualOutput);
|
|
}
|
|
|
|
TEST_F(PrintFormatterTest, GivenPrintfSpecialVectorFormatWhenVectorOfIntsThenInsertAllValues) {
|
|
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[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::maxPrintfOutputLength); });
|
|
|
|
EXPECT_STREQ("1,2", actualOutput);
|
|
}
|
|
TEST_F(PrintFormatterTest, GivenPrintfFormatWhenVectorOfLongsThenInsertAllValues) {
|
|
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[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::maxPrintfOutputLength); });
|
|
|
|
EXPECT_STREQ("1,2", actualOutput);
|
|
}
|
|
|
|
TEST_F(PrintFormatterTest, GivenPrintfFormatWhenVectorOfFloatsThenInsertAllValues) {
|
|
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[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::maxPrintfOutputLength); });
|
|
|
|
EXPECT_STREQ("1.000000,2.000000", actualOutput);
|
|
}
|
|
|
|
TEST_F(PrintFormatterTest, GivenPrintfFormatWhenVectorOfDoublesThenInsertAllValues) {
|
|
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[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::maxPrintfOutputLength); });
|
|
|
|
EXPECT_STREQ("1.000000,2.000000", actualOutput);
|
|
}
|
|
|
|
TEST_F(PrintFormatterTest, GivenPrintfFormatWhenPointerThenInsertAddress) {
|
|
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[PrintFormatter::maxPrintfOutputLength];
|
|
char referenceOutput[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
snprintf(referenceOutput, sizeof(referenceOutput), "%p", reinterpret_cast<void *>(&temp));
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::maxPrintfOutputLength); });
|
|
|
|
EXPECT_STREQ(referenceOutput, actualOutput);
|
|
}
|
|
|
|
TEST_F(PrintFormatterTest, GivenPrintfFormatWhenPointerWith32BitKernelThenPrint32BitPointer) {
|
|
auto stringIndex = injectFormatString("%p");
|
|
storeData(stringIndex);
|
|
kernelInfo->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[PrintFormatter::maxPrintfOutputLength];
|
|
char referenceOutput[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
snprintf(referenceOutput, sizeof(referenceOutput), "%p", pointer);
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::maxPrintfOutputLength); });
|
|
|
|
EXPECT_STREQ(referenceOutput, actualOutput);
|
|
}
|
|
|
|
TEST_F(PrintFormatterTest, GivenPrintfFormatWhen2ByteVectorsThenParseDataBufferProperly) {
|
|
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[PrintFormatter::maxPrintfOutputLength];
|
|
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::maxPrintfOutputLength); });
|
|
|
|
EXPECT_STREQ("1,2,3,4 1,2,3,4", actualOutput);
|
|
}
|
|
|
|
TEST_F(PrintFormatterTest, GivenEmptyBufferWhenPrintingThenFailSafely) {
|
|
char actualOutput[PrintFormatter::maxPrintfOutputLength];
|
|
actualOutput[0] = 0;
|
|
printFormatter->printKernelOutput([&actualOutput](char *str) { strncpy_s(actualOutput, PrintFormatter::maxPrintfOutputLength, str, PrintFormatter::maxPrintfOutputLength); });
|
|
EXPECT_STREQ("", actualOutput);
|
|
}
|
|
|
|
TEST(printToSTDOUTTest, GivenStringWhenPrintingToSTDOUTThenExpectOutput) {
|
|
testing::internal::CaptureStdout();
|
|
printToSTDOUT("test");
|
|
std::string output = testing::internal::GetCapturedStdout();
|
|
EXPECT_STREQ("test", output.c_str());
|
|
}
|