1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * drawElements Quality Program Test Executor
3e5c31af7Sopenharmony_ci * ------------------------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright 2014 The Android Open Source Project
6e5c31af7Sopenharmony_ci *
7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License.
9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at
10e5c31af7Sopenharmony_ci *
11e5c31af7Sopenharmony_ci *      http://www.apache.org/licenses/LICENSE-2.0
12e5c31af7Sopenharmony_ci *
13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and
17e5c31af7Sopenharmony_ci * limitations under the License.
18e5c31af7Sopenharmony_ci *
19e5c31af7Sopenharmony_ci *//*!
20e5c31af7Sopenharmony_ci * \file
21e5c31af7Sopenharmony_ci * \brief Test log writer.
22e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
23e5c31af7Sopenharmony_ci
24e5c31af7Sopenharmony_ci#include "xeTestLogWriter.hpp"
25e5c31af7Sopenharmony_ci#include "xeXMLWriter.hpp"
26e5c31af7Sopenharmony_ci#include "deStringUtil.hpp"
27e5c31af7Sopenharmony_ci
28e5c31af7Sopenharmony_ci#include <fstream>
29e5c31af7Sopenharmony_ci
30e5c31af7Sopenharmony_cinamespace xe
31e5c31af7Sopenharmony_ci{
32e5c31af7Sopenharmony_ci
33e5c31af7Sopenharmony_ci/* Batch result writer. */
34e5c31af7Sopenharmony_ci
35e5c31af7Sopenharmony_cistruct ContainerValue
36e5c31af7Sopenharmony_ci{
37e5c31af7Sopenharmony_ci	ContainerValue (const std::string& value_)	: value(value_) {}
38e5c31af7Sopenharmony_ci	ContainerValue (const char* value_)			: value(value_) {}
39e5c31af7Sopenharmony_ci	std::string value;
40e5c31af7Sopenharmony_ci};
41e5c31af7Sopenharmony_ci
42e5c31af7Sopenharmony_cistd::ostream& operator<< (std::ostream& stream, const ContainerValue& value)
43e5c31af7Sopenharmony_ci{
44e5c31af7Sopenharmony_ci	if (value.value.find(' ') != std::string::npos)
45e5c31af7Sopenharmony_ci	{
46e5c31af7Sopenharmony_ci		// Escape.
47e5c31af7Sopenharmony_ci		stream << '"';
48e5c31af7Sopenharmony_ci		for (std::string::const_iterator i = value.value.begin(); i != value.value.end(); i++)
49e5c31af7Sopenharmony_ci		{
50e5c31af7Sopenharmony_ci			if (*i == '"' || *i == '\\')
51e5c31af7Sopenharmony_ci				stream << '\\';
52e5c31af7Sopenharmony_ci			stream << *i;
53e5c31af7Sopenharmony_ci		}
54e5c31af7Sopenharmony_ci		stream << '"';
55e5c31af7Sopenharmony_ci	}
56e5c31af7Sopenharmony_ci	else
57e5c31af7Sopenharmony_ci		stream << value.value;
58e5c31af7Sopenharmony_ci
59e5c31af7Sopenharmony_ci	return stream;
60e5c31af7Sopenharmony_ci}
61e5c31af7Sopenharmony_ci
62e5c31af7Sopenharmony_cistatic void writeSessionInfo (const SessionInfo& info, std::ostream& stream)
63e5c31af7Sopenharmony_ci{
64e5c31af7Sopenharmony_ci	if (!info.releaseName.empty())
65e5c31af7Sopenharmony_ci		stream << "#sessionInfo releaseName " << ContainerValue(info.releaseName) << "\n";
66e5c31af7Sopenharmony_ci
67e5c31af7Sopenharmony_ci	if (!info.releaseId.empty())
68e5c31af7Sopenharmony_ci		stream << "#sessionInfo releaseId " << ContainerValue(info.releaseId) << "\n";
69e5c31af7Sopenharmony_ci
70e5c31af7Sopenharmony_ci	if (!info.targetName.empty())
71e5c31af7Sopenharmony_ci		stream << "#sessionInfo targetName " << ContainerValue(info.targetName) << "\n";
72e5c31af7Sopenharmony_ci
73e5c31af7Sopenharmony_ci	if (!info.candyTargetName.empty())
74e5c31af7Sopenharmony_ci		stream << "#sessionInfo candyTargetName " << ContainerValue(info.candyTargetName) << "\n";
75e5c31af7Sopenharmony_ci
76e5c31af7Sopenharmony_ci	if (!info.configName.empty())
77e5c31af7Sopenharmony_ci		stream << "#sessionInfo configName " << ContainerValue(info.configName) << "\n";
78e5c31af7Sopenharmony_ci
79e5c31af7Sopenharmony_ci	if (!info.resultName.empty())
80e5c31af7Sopenharmony_ci		stream << "#sessionInfo resultName " << ContainerValue(info.resultName) << "\n";
81e5c31af7Sopenharmony_ci
82e5c31af7Sopenharmony_ci	// \note Current format uses unescaped timestamps for some strange reason.
83e5c31af7Sopenharmony_ci	if (!info.timestamp.empty())
84e5c31af7Sopenharmony_ci		stream << "#sessionInfo timestamp " << info.timestamp << "\n";
85e5c31af7Sopenharmony_ci}
86e5c31af7Sopenharmony_ci
87e5c31af7Sopenharmony_cistatic void writeTestCase (const TestCaseResultData& caseData, std::ostream& stream)
88e5c31af7Sopenharmony_ci{
89e5c31af7Sopenharmony_ci	stream << "\n#beginTestCaseResult " << caseData.getTestCasePath() << "\n";
90e5c31af7Sopenharmony_ci
91e5c31af7Sopenharmony_ci	if (caseData.getDataSize() > 0)
92e5c31af7Sopenharmony_ci	{
93e5c31af7Sopenharmony_ci		stream.write((const char*)caseData.getData(), caseData.getDataSize());
94e5c31af7Sopenharmony_ci
95e5c31af7Sopenharmony_ci		deUint8 lastCh = caseData.getData()[caseData.getDataSize()-1];
96e5c31af7Sopenharmony_ci		if (lastCh != '\n' && lastCh != '\r')
97e5c31af7Sopenharmony_ci			stream << "\n";
98e5c31af7Sopenharmony_ci	}
99e5c31af7Sopenharmony_ci
100e5c31af7Sopenharmony_ci	TestStatusCode dataCode = caseData.getStatusCode();
101e5c31af7Sopenharmony_ci	if (dataCode == TESTSTATUSCODE_CRASH	||
102e5c31af7Sopenharmony_ci		dataCode == TESTSTATUSCODE_TIMEOUT	||
103e5c31af7Sopenharmony_ci		dataCode == TESTSTATUSCODE_TERMINATED)
104e5c31af7Sopenharmony_ci		stream << "#terminateTestCaseResult " << getTestStatusCodeName(dataCode) << "\n";
105e5c31af7Sopenharmony_ci	else
106e5c31af7Sopenharmony_ci		stream << "#endTestCaseResult\n";
107e5c31af7Sopenharmony_ci}
108e5c31af7Sopenharmony_ci
109e5c31af7Sopenharmony_civoid writeTestLog (const BatchResult& result, std::ostream& stream)
110e5c31af7Sopenharmony_ci{
111e5c31af7Sopenharmony_ci	writeSessionInfo(result.getSessionInfo(), stream);
112e5c31af7Sopenharmony_ci
113e5c31af7Sopenharmony_ci	stream << "#beginSession\n";
114e5c31af7Sopenharmony_ci
115e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < result.getNumTestCaseResults(); ndx++)
116e5c31af7Sopenharmony_ci	{
117e5c31af7Sopenharmony_ci		ConstTestCaseResultPtr caseData = result.getTestCaseResult(ndx);
118e5c31af7Sopenharmony_ci		writeTestCase(*caseData, stream);
119e5c31af7Sopenharmony_ci	}
120e5c31af7Sopenharmony_ci
121e5c31af7Sopenharmony_ci	stream << "\n#endSession\n";
122e5c31af7Sopenharmony_ci}
123e5c31af7Sopenharmony_ci
124e5c31af7Sopenharmony_civoid writeBatchResultToFile (const BatchResult& result, const char* filename)
125e5c31af7Sopenharmony_ci{
126e5c31af7Sopenharmony_ci	std::ofstream str(filename, std::ofstream::binary|std::ofstream::trunc);
127e5c31af7Sopenharmony_ci	writeTestLog(result, str);
128e5c31af7Sopenharmony_ci	str.close();
129e5c31af7Sopenharmony_ci}
130e5c31af7Sopenharmony_ci
131e5c31af7Sopenharmony_ci/* Test result log writer. */
132e5c31af7Sopenharmony_ci
133e5c31af7Sopenharmony_cistatic const char* getImageFormatName (ri::Image::Format format)
134e5c31af7Sopenharmony_ci{
135e5c31af7Sopenharmony_ci	switch (format)
136e5c31af7Sopenharmony_ci	{
137e5c31af7Sopenharmony_ci		case ri::Image::FORMAT_RGB888:		return "RGB888";
138e5c31af7Sopenharmony_ci		case ri::Image::FORMAT_RGBA8888:	return "RGBA8888";
139e5c31af7Sopenharmony_ci		default:
140e5c31af7Sopenharmony_ci			DE_ASSERT(false);
141e5c31af7Sopenharmony_ci			return DE_NULL;
142e5c31af7Sopenharmony_ci	}
143e5c31af7Sopenharmony_ci}
144e5c31af7Sopenharmony_ci
145e5c31af7Sopenharmony_cistatic const char* getImageCompressionName (ri::Image::Compression compression)
146e5c31af7Sopenharmony_ci{
147e5c31af7Sopenharmony_ci	switch (compression)
148e5c31af7Sopenharmony_ci	{
149e5c31af7Sopenharmony_ci		case ri::Image::COMPRESSION_NONE:	return "None";
150e5c31af7Sopenharmony_ci		case ri::Image::COMPRESSION_PNG:	return "PNG";
151e5c31af7Sopenharmony_ci		default:
152e5c31af7Sopenharmony_ci			DE_ASSERT(false);
153e5c31af7Sopenharmony_ci			return DE_NULL;
154e5c31af7Sopenharmony_ci	}
155e5c31af7Sopenharmony_ci}
156e5c31af7Sopenharmony_ci
157e5c31af7Sopenharmony_cistatic const char* getSampleValueTagName (ri::ValueInfo::ValueTag tag)
158e5c31af7Sopenharmony_ci{
159e5c31af7Sopenharmony_ci	switch (tag)
160e5c31af7Sopenharmony_ci	{
161e5c31af7Sopenharmony_ci		case ri::ValueInfo::VALUETAG_PREDICTOR:	return "Predictor";
162e5c31af7Sopenharmony_ci		case ri::ValueInfo::VALUETAG_RESPONSE:	return "Response";
163e5c31af7Sopenharmony_ci		default:
164e5c31af7Sopenharmony_ci			DE_ASSERT(false);
165e5c31af7Sopenharmony_ci			return DE_NULL;
166e5c31af7Sopenharmony_ci	}
167e5c31af7Sopenharmony_ci}
168e5c31af7Sopenharmony_ci
169e5c31af7Sopenharmony_ciinline const char* getBoolName (bool val)
170e5c31af7Sopenharmony_ci{
171e5c31af7Sopenharmony_ci	return val ? "True" : "False";
172e5c31af7Sopenharmony_ci}
173e5c31af7Sopenharmony_ci
174e5c31af7Sopenharmony_ci// \todo [2012-09-07 pyry] Move to tcutil?
175e5c31af7Sopenharmony_ciclass Base64Formatter
176e5c31af7Sopenharmony_ci{
177e5c31af7Sopenharmony_cipublic:
178e5c31af7Sopenharmony_ci	const deUint8*	data;
179e5c31af7Sopenharmony_ci	int				numBytes;
180e5c31af7Sopenharmony_ci
181e5c31af7Sopenharmony_ci	Base64Formatter (const deUint8* data_, int numBytes_) : data(data_), numBytes(numBytes_) {}
182e5c31af7Sopenharmony_ci};
183e5c31af7Sopenharmony_ci
184e5c31af7Sopenharmony_cistd::ostream& operator<< (std::ostream& str, const Base64Formatter& fmt)
185e5c31af7Sopenharmony_ci{
186e5c31af7Sopenharmony_ci	static const char s_base64Table[64] =
187e5c31af7Sopenharmony_ci	{
188e5c31af7Sopenharmony_ci		'A','B','C','D','E','F','G','H','I','J','K','L','M',
189e5c31af7Sopenharmony_ci		'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
190e5c31af7Sopenharmony_ci		'a','b','c','d','e','f','g','h','i','j','k','l','m',
191e5c31af7Sopenharmony_ci		'n','o','p','q','r','s','t','u','v','w','x','y','z',
192e5c31af7Sopenharmony_ci		'0','1','2','3','4','5','6','7','8','9','+','/'
193e5c31af7Sopenharmony_ci	};
194e5c31af7Sopenharmony_ci
195e5c31af7Sopenharmony_ci	const deUint8*	data		= fmt.data;
196e5c31af7Sopenharmony_ci	int				numBytes	= fmt.numBytes;
197e5c31af7Sopenharmony_ci	int				srcNdx		= 0;
198e5c31af7Sopenharmony_ci
199e5c31af7Sopenharmony_ci	DE_ASSERT(data && (numBytes > 0));
200e5c31af7Sopenharmony_ci
201e5c31af7Sopenharmony_ci	/* Loop all input chars. */
202e5c31af7Sopenharmony_ci	while (srcNdx < numBytes)
203e5c31af7Sopenharmony_ci	{
204e5c31af7Sopenharmony_ci		int		numRead	= de::min(3, numBytes - srcNdx);
205e5c31af7Sopenharmony_ci		deUint8	s0		= data[srcNdx];
206e5c31af7Sopenharmony_ci		deUint8	s1		= (numRead >= 2) ? data[srcNdx+1] : 0;
207e5c31af7Sopenharmony_ci		deUint8	s2		= (numRead >= 3) ? data[srcNdx+2] : 0;
208e5c31af7Sopenharmony_ci		char	d[4];
209e5c31af7Sopenharmony_ci
210e5c31af7Sopenharmony_ci		srcNdx += numRead;
211e5c31af7Sopenharmony_ci
212e5c31af7Sopenharmony_ci		d[0] = s_base64Table[s0 >> 2];
213e5c31af7Sopenharmony_ci		d[1] = s_base64Table[((s0&0x3)<<4) | (s1>>4)];
214e5c31af7Sopenharmony_ci		d[2] = s_base64Table[((s1&0xF)<<2) | (s2>>6)];
215e5c31af7Sopenharmony_ci		d[3] = s_base64Table[s2&0x3F];
216e5c31af7Sopenharmony_ci
217e5c31af7Sopenharmony_ci		if (numRead < 3) d[3] = '=';
218e5c31af7Sopenharmony_ci		if (numRead < 2) d[2] = '=';
219e5c31af7Sopenharmony_ci
220e5c31af7Sopenharmony_ci		/* Write data. */
221e5c31af7Sopenharmony_ci		str.write(&d[0], sizeof(d));
222e5c31af7Sopenharmony_ci	}
223e5c31af7Sopenharmony_ci
224e5c31af7Sopenharmony_ci	return str;
225e5c31af7Sopenharmony_ci}
226e5c31af7Sopenharmony_ci
227e5c31af7Sopenharmony_ciinline Base64Formatter toBase64 (const deUint8* bytes, int numBytes) { return Base64Formatter(bytes, numBytes); }
228e5c31af7Sopenharmony_ci
229e5c31af7Sopenharmony_cistatic const char* getStatusName (bool value)
230e5c31af7Sopenharmony_ci{
231e5c31af7Sopenharmony_ci	return value ? "OK" : "Fail";
232e5c31af7Sopenharmony_ci}
233e5c31af7Sopenharmony_ci
234e5c31af7Sopenharmony_cistatic void writeResultItem (const ri::Item& item, xml::Writer& dst)
235e5c31af7Sopenharmony_ci{
236e5c31af7Sopenharmony_ci	using xml::Writer;
237e5c31af7Sopenharmony_ci
238e5c31af7Sopenharmony_ci	switch (item.getType())
239e5c31af7Sopenharmony_ci	{
240e5c31af7Sopenharmony_ci		case ri::TYPE_RESULT:
241e5c31af7Sopenharmony_ci			// Ignored here, written at end.
242e5c31af7Sopenharmony_ci			break;
243e5c31af7Sopenharmony_ci
244e5c31af7Sopenharmony_ci		case ri::TYPE_TEXT:
245e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("Text") << static_cast<const ri::Text&>(item).text << Writer::EndElement;
246e5c31af7Sopenharmony_ci			break;
247e5c31af7Sopenharmony_ci
248e5c31af7Sopenharmony_ci		case ri::TYPE_NUMBER:
249e5c31af7Sopenharmony_ci		{
250e5c31af7Sopenharmony_ci			const ri::Number& number = static_cast<const ri::Number&>(item);
251e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("Number")
252e5c31af7Sopenharmony_ci				<< Writer::Attribute("Name",		number.name)
253e5c31af7Sopenharmony_ci				<< Writer::Attribute("Description",	number.description)
254e5c31af7Sopenharmony_ci				<< Writer::Attribute("Unit",		number.unit)
255e5c31af7Sopenharmony_ci				<< Writer::Attribute("Tag",			number.tag)
256e5c31af7Sopenharmony_ci				<< number.value
257e5c31af7Sopenharmony_ci				<< Writer::EndElement;
258e5c31af7Sopenharmony_ci			break;
259e5c31af7Sopenharmony_ci		}
260e5c31af7Sopenharmony_ci
261e5c31af7Sopenharmony_ci		case ri::TYPE_IMAGE:
262e5c31af7Sopenharmony_ci		{
263e5c31af7Sopenharmony_ci			const ri::Image& image = static_cast<const ri::Image&>(item);
264e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("Image")
265e5c31af7Sopenharmony_ci				<< Writer::Attribute("Name",			image.name)
266e5c31af7Sopenharmony_ci				<< Writer::Attribute("Description",		image.description)
267e5c31af7Sopenharmony_ci				<< Writer::Attribute("Width",			de::toString(image.width))
268e5c31af7Sopenharmony_ci				<< Writer::Attribute("Height",			de::toString(image.height))
269e5c31af7Sopenharmony_ci				<< Writer::Attribute("Format",			getImageFormatName(image.format))
270e5c31af7Sopenharmony_ci				<< Writer::Attribute("CompressionMode",	getImageCompressionName(image.compression))
271e5c31af7Sopenharmony_ci				<< toBase64(&image.data[0], (int)image.data.size())
272e5c31af7Sopenharmony_ci				<< Writer::EndElement;
273e5c31af7Sopenharmony_ci			break;
274e5c31af7Sopenharmony_ci		}
275e5c31af7Sopenharmony_ci
276e5c31af7Sopenharmony_ci		case ri::TYPE_IMAGESET:
277e5c31af7Sopenharmony_ci		{
278e5c31af7Sopenharmony_ci			const ri::ImageSet& imageSet = static_cast<const ri::ImageSet&>(item);
279e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("ImageSet")
280e5c31af7Sopenharmony_ci				<< Writer::Attribute("Name",		imageSet.name)
281e5c31af7Sopenharmony_ci				<< Writer::Attribute("Description",	imageSet.description);
282e5c31af7Sopenharmony_ci
283e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < imageSet.images.getNumItems(); ndx++)
284e5c31af7Sopenharmony_ci				writeResultItem(imageSet.images.getItem(ndx), dst);
285e5c31af7Sopenharmony_ci
286e5c31af7Sopenharmony_ci			dst << Writer::EndElement;
287e5c31af7Sopenharmony_ci			break;
288e5c31af7Sopenharmony_ci		}
289e5c31af7Sopenharmony_ci
290e5c31af7Sopenharmony_ci		case ri::TYPE_SHADER:
291e5c31af7Sopenharmony_ci		{
292e5c31af7Sopenharmony_ci			const ri::Shader&	shader		= static_cast<const ri::Shader&>(item);
293e5c31af7Sopenharmony_ci			const char*			tagName		= DE_NULL;
294e5c31af7Sopenharmony_ci
295e5c31af7Sopenharmony_ci			switch (shader.shaderType)
296e5c31af7Sopenharmony_ci			{
297e5c31af7Sopenharmony_ci				case ri::Shader::SHADERTYPE_VERTEX:				tagName = "VertexShader";			break;
298e5c31af7Sopenharmony_ci				case ri::Shader::SHADERTYPE_FRAGMENT:			tagName = "FragmentShader";			break;
299e5c31af7Sopenharmony_ci				case ri::Shader::SHADERTYPE_GEOMETRY:			tagName = "GeometryShader";			break;
300e5c31af7Sopenharmony_ci				case ri::Shader::SHADERTYPE_TESS_CONTROL:		tagName = "TessControlShader";		break;
301e5c31af7Sopenharmony_ci				case ri::Shader::SHADERTYPE_TESS_EVALUATION:	tagName = "TessEvaluationShader";	break;
302e5c31af7Sopenharmony_ci				case ri::Shader::SHADERTYPE_COMPUTE:			tagName = "ComputeShader";			break;
303e5c31af7Sopenharmony_ci				case ri::Shader::SHADERTYPE_RAYGEN:				tagName = "RaygenShader";			break;
304e5c31af7Sopenharmony_ci				case ri::Shader::SHADERTYPE_ANY_HIT:			tagName = "AnyHitShader";			break;
305e5c31af7Sopenharmony_ci				case ri::Shader::SHADERTYPE_CLOSEST_HIT:		tagName = "ClosestHitShader";		break;
306e5c31af7Sopenharmony_ci				case ri::Shader::SHADERTYPE_MISS:				tagName = "MissShader";				break;
307e5c31af7Sopenharmony_ci				case ri::Shader::SHADERTYPE_INTERSECTION:		tagName = "IntersectionShader";		break;
308e5c31af7Sopenharmony_ci				case ri::Shader::SHADERTYPE_CALLABLE:			tagName = "CallableShader";			break;
309e5c31af7Sopenharmony_ci				case ri::Shader::SHADERTYPE_TASK:				tagName = "TaskShader";				break;
310e5c31af7Sopenharmony_ci				case ri::Shader::SHADERTYPE_MESH:				tagName = "MeshShader";				break;
311e5c31af7Sopenharmony_ci
312e5c31af7Sopenharmony_ci				default:
313e5c31af7Sopenharmony_ci					throw Error("Unknown shader type");
314e5c31af7Sopenharmony_ci			}
315e5c31af7Sopenharmony_ci
316e5c31af7Sopenharmony_ci			dst << Writer::BeginElement(tagName)
317e5c31af7Sopenharmony_ci				<< Writer::Attribute("CompileStatus",	getStatusName(shader.compileStatus));
318e5c31af7Sopenharmony_ci
319e5c31af7Sopenharmony_ci			writeResultItem(shader.source, dst);
320e5c31af7Sopenharmony_ci			writeResultItem(shader.infoLog, dst);
321e5c31af7Sopenharmony_ci
322e5c31af7Sopenharmony_ci			dst << Writer::EndElement;
323e5c31af7Sopenharmony_ci			break;
324e5c31af7Sopenharmony_ci		}
325e5c31af7Sopenharmony_ci
326e5c31af7Sopenharmony_ci		case ri::TYPE_SHADERPROGRAM:
327e5c31af7Sopenharmony_ci		{
328e5c31af7Sopenharmony_ci			const ri::ShaderProgram& program = static_cast<const ri::ShaderProgram&>(item);
329e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("ShaderProgram")
330e5c31af7Sopenharmony_ci				<< Writer::Attribute("LinkStatus",	getStatusName(program.linkStatus));
331e5c31af7Sopenharmony_ci
332e5c31af7Sopenharmony_ci			writeResultItem(program.linkInfoLog, dst);
333e5c31af7Sopenharmony_ci
334e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < program.shaders.getNumItems(); ndx++)
335e5c31af7Sopenharmony_ci				writeResultItem(program.shaders.getItem(ndx), dst);
336e5c31af7Sopenharmony_ci
337e5c31af7Sopenharmony_ci			dst << Writer::EndElement;
338e5c31af7Sopenharmony_ci			break;
339e5c31af7Sopenharmony_ci		}
340e5c31af7Sopenharmony_ci
341e5c31af7Sopenharmony_ci		case ri::TYPE_SHADERSOURCE:
342e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("ShaderSource") << static_cast<const ri::ShaderSource&>(item).source << Writer::EndElement;
343e5c31af7Sopenharmony_ci			break;
344e5c31af7Sopenharmony_ci
345e5c31af7Sopenharmony_ci		case ri::TYPE_SPIRVSOURCE:
346e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("SpirVAssemblySource") << static_cast<const ri::SpirVSource&>(item).source << Writer::EndElement;
347e5c31af7Sopenharmony_ci			break;
348e5c31af7Sopenharmony_ci
349e5c31af7Sopenharmony_ci		case ri::TYPE_INFOLOG:
350e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("InfoLog") << static_cast<const ri::InfoLog&>(item).log << Writer::EndElement;
351e5c31af7Sopenharmony_ci			break;
352e5c31af7Sopenharmony_ci
353e5c31af7Sopenharmony_ci		case ri::TYPE_SECTION:
354e5c31af7Sopenharmony_ci		{
355e5c31af7Sopenharmony_ci			const ri::Section& section = static_cast<const ri::Section&>(item);
356e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("Section")
357e5c31af7Sopenharmony_ci				<< Writer::Attribute("Name",		section.name)
358e5c31af7Sopenharmony_ci				<< Writer::Attribute("Description",	section.description);
359e5c31af7Sopenharmony_ci
360e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < section.items.getNumItems(); ndx++)
361e5c31af7Sopenharmony_ci				writeResultItem(section.items.getItem(ndx), dst);
362e5c31af7Sopenharmony_ci
363e5c31af7Sopenharmony_ci			dst << Writer::EndElement;
364e5c31af7Sopenharmony_ci			break;
365e5c31af7Sopenharmony_ci		}
366e5c31af7Sopenharmony_ci
367e5c31af7Sopenharmony_ci		case ri::TYPE_KERNELSOURCE:
368e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("KernelSource") << static_cast<const ri::KernelSource&>(item).source << Writer::EndElement;
369e5c31af7Sopenharmony_ci			break;
370e5c31af7Sopenharmony_ci
371e5c31af7Sopenharmony_ci		case ri::TYPE_COMPILEINFO:
372e5c31af7Sopenharmony_ci		{
373e5c31af7Sopenharmony_ci			const ri::CompileInfo& compileInfo = static_cast<const ri::CompileInfo&>(item);
374e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("CompileInfo")
375e5c31af7Sopenharmony_ci				<< Writer::Attribute("Name",			compileInfo.name)
376e5c31af7Sopenharmony_ci				<< Writer::Attribute("Description",		compileInfo.description)
377e5c31af7Sopenharmony_ci				<< Writer::Attribute("CompileStatus",	getStatusName(compileInfo.compileStatus));
378e5c31af7Sopenharmony_ci
379e5c31af7Sopenharmony_ci			writeResultItem(compileInfo.infoLog, dst);
380e5c31af7Sopenharmony_ci
381e5c31af7Sopenharmony_ci			dst << Writer::EndElement;
382e5c31af7Sopenharmony_ci			break;
383e5c31af7Sopenharmony_ci		}
384e5c31af7Sopenharmony_ci
385e5c31af7Sopenharmony_ci		case ri::TYPE_EGLCONFIG:
386e5c31af7Sopenharmony_ci		{
387e5c31af7Sopenharmony_ci			const ri::EglConfig& config = static_cast<const ri::EglConfig&>(item);
388e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("EglConfig")
389e5c31af7Sopenharmony_ci				<< Writer::Attribute("BufferSize",				de::toString(config.bufferSize))
390e5c31af7Sopenharmony_ci				<< Writer::Attribute("RedSize",					de::toString(config.redSize))
391e5c31af7Sopenharmony_ci				<< Writer::Attribute("GreenSize",				de::toString(config.greenSize))
392e5c31af7Sopenharmony_ci				<< Writer::Attribute("BlueSize",				de::toString(config.blueSize))
393e5c31af7Sopenharmony_ci				<< Writer::Attribute("LuminanceSize",			de::toString(config.luminanceSize))
394e5c31af7Sopenharmony_ci				<< Writer::Attribute("AlphaSize",				de::toString(config.alphaSize))
395e5c31af7Sopenharmony_ci				<< Writer::Attribute("AlphaMaskSize",			de::toString(config.alphaMaskSize))
396e5c31af7Sopenharmony_ci				<< Writer::Attribute("BindToTextureRGB",		getBoolName(config.bindToTextureRGB))
397e5c31af7Sopenharmony_ci				<< Writer::Attribute("BindToTextureRGBA",		getBoolName(config.bindToTextureRGBA))
398e5c31af7Sopenharmony_ci				<< Writer::Attribute("ColorBufferType",			config.colorBufferType)
399e5c31af7Sopenharmony_ci				<< Writer::Attribute("ConfigCaveat",			config.configCaveat)
400e5c31af7Sopenharmony_ci				<< Writer::Attribute("ConfigID",				de::toString(config.configID))
401e5c31af7Sopenharmony_ci				<< Writer::Attribute("Conformant",				config.conformant)
402e5c31af7Sopenharmony_ci				<< Writer::Attribute("DepthSize",				de::toString(config.depthSize))
403e5c31af7Sopenharmony_ci				<< Writer::Attribute("Level",					de::toString(config.level))
404e5c31af7Sopenharmony_ci				<< Writer::Attribute("MaxPBufferWidth",			de::toString(config.maxPBufferWidth))
405e5c31af7Sopenharmony_ci				<< Writer::Attribute("MaxPBufferHeight",		de::toString(config.maxPBufferHeight))
406e5c31af7Sopenharmony_ci				<< Writer::Attribute("MaxPBufferPixels",		de::toString(config.maxPBufferPixels))
407e5c31af7Sopenharmony_ci				<< Writer::Attribute("MaxSwapInterval",			de::toString(config.maxSwapInterval))
408e5c31af7Sopenharmony_ci				<< Writer::Attribute("MinSwapInterval",			de::toString(config.minSwapInterval))
409e5c31af7Sopenharmony_ci				<< Writer::Attribute("NativeRenderable",		getBoolName(config.nativeRenderable))
410e5c31af7Sopenharmony_ci				<< Writer::Attribute("RenderableType",			config.renderableType)
411e5c31af7Sopenharmony_ci				<< Writer::Attribute("SampleBuffers",			de::toString(config.sampleBuffers))
412e5c31af7Sopenharmony_ci				<< Writer::Attribute("Samples",					de::toString(config.samples))
413e5c31af7Sopenharmony_ci				<< Writer::Attribute("StencilSize",				de::toString(config.stencilSize))
414e5c31af7Sopenharmony_ci				<< Writer::Attribute("SurfaceTypes",			config.surfaceTypes)
415e5c31af7Sopenharmony_ci				<< Writer::Attribute("TransparentType",			config.transparentType)
416e5c31af7Sopenharmony_ci				<< Writer::Attribute("TransparentRedValue",		de::toString(config.transparentRedValue))
417e5c31af7Sopenharmony_ci				<< Writer::Attribute("TransparentGreenValue",	de::toString(config.transparentGreenValue))
418e5c31af7Sopenharmony_ci				<< Writer::Attribute("TransparentBlueValue",	de::toString(config.transparentBlueValue))
419e5c31af7Sopenharmony_ci				<< Writer::EndElement;
420e5c31af7Sopenharmony_ci			break;
421e5c31af7Sopenharmony_ci		}
422e5c31af7Sopenharmony_ci
423e5c31af7Sopenharmony_ci		case ri::TYPE_EGLCONFIGSET:
424e5c31af7Sopenharmony_ci		{
425e5c31af7Sopenharmony_ci			const ri::EglConfigSet& configSet = static_cast<const ri::EglConfigSet&>(item);
426e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("EglConfigSet")
427e5c31af7Sopenharmony_ci				<< Writer::Attribute("Name",			configSet.name)
428e5c31af7Sopenharmony_ci				<< Writer::Attribute("Description",		configSet.description);
429e5c31af7Sopenharmony_ci
430e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < configSet.configs.getNumItems(); ndx++)
431e5c31af7Sopenharmony_ci				writeResultItem(configSet.configs.getItem(ndx), dst);
432e5c31af7Sopenharmony_ci
433e5c31af7Sopenharmony_ci			dst << Writer::EndElement;
434e5c31af7Sopenharmony_ci			break;
435e5c31af7Sopenharmony_ci		}
436e5c31af7Sopenharmony_ci
437e5c31af7Sopenharmony_ci		case ri::TYPE_SAMPLELIST:
438e5c31af7Sopenharmony_ci		{
439e5c31af7Sopenharmony_ci			const ri::SampleList& list = static_cast<const ri::SampleList&>(item);
440e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("SampleList")
441e5c31af7Sopenharmony_ci				<< Writer::Attribute("Name",		list.name)
442e5c31af7Sopenharmony_ci				<< Writer::Attribute("Description",	list.description);
443e5c31af7Sopenharmony_ci
444e5c31af7Sopenharmony_ci			writeResultItem(list.sampleInfo, dst);
445e5c31af7Sopenharmony_ci
446e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < list.samples.getNumItems(); ndx++)
447e5c31af7Sopenharmony_ci				writeResultItem(list.samples.getItem(ndx), dst);
448e5c31af7Sopenharmony_ci
449e5c31af7Sopenharmony_ci			dst << Writer::EndElement;
450e5c31af7Sopenharmony_ci			break;
451e5c31af7Sopenharmony_ci		}
452e5c31af7Sopenharmony_ci
453e5c31af7Sopenharmony_ci		case ri::TYPE_SAMPLEINFO:
454e5c31af7Sopenharmony_ci		{
455e5c31af7Sopenharmony_ci			const ri::SampleInfo& info = static_cast<const ri::SampleInfo&>(item);
456e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("SampleInfo");
457e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < info.valueInfos.getNumItems(); ndx++)
458e5c31af7Sopenharmony_ci				writeResultItem(info.valueInfos.getItem(ndx), dst);
459e5c31af7Sopenharmony_ci			dst << Writer::EndElement;
460e5c31af7Sopenharmony_ci			break;
461e5c31af7Sopenharmony_ci		}
462e5c31af7Sopenharmony_ci
463e5c31af7Sopenharmony_ci		case ri::TYPE_VALUEINFO:
464e5c31af7Sopenharmony_ci		{
465e5c31af7Sopenharmony_ci			const ri::ValueInfo& info = static_cast<const ri::ValueInfo&>(item);
466e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("ValueInfo")
467e5c31af7Sopenharmony_ci				<< Writer::Attribute("Name",		info.name)
468e5c31af7Sopenharmony_ci				<< Writer::Attribute("Description",	info.description)
469e5c31af7Sopenharmony_ci				<< Writer::Attribute("Tag",			getSampleValueTagName(info.tag));
470e5c31af7Sopenharmony_ci			if (!info.unit.empty())
471e5c31af7Sopenharmony_ci				dst << Writer::Attribute("Unit", info.unit);
472e5c31af7Sopenharmony_ci			dst << Writer::EndElement;
473e5c31af7Sopenharmony_ci			break;
474e5c31af7Sopenharmony_ci		}
475e5c31af7Sopenharmony_ci
476e5c31af7Sopenharmony_ci		case ri::TYPE_SAMPLE:
477e5c31af7Sopenharmony_ci		{
478e5c31af7Sopenharmony_ci			const ri::Sample& sample = static_cast<const ri::Sample&>(item);
479e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("Sample");
480e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < sample.values.getNumItems(); ndx++)
481e5c31af7Sopenharmony_ci				writeResultItem(sample.values.getItem(ndx), dst);
482e5c31af7Sopenharmony_ci			dst << Writer::EndElement;
483e5c31af7Sopenharmony_ci			break;
484e5c31af7Sopenharmony_ci		}
485e5c31af7Sopenharmony_ci
486e5c31af7Sopenharmony_ci		case ri::TYPE_SAMPLEVALUE:
487e5c31af7Sopenharmony_ci		{
488e5c31af7Sopenharmony_ci			const ri::SampleValue& value = static_cast<const ri::SampleValue&>(item);
489e5c31af7Sopenharmony_ci			dst << Writer::BeginElement("Value")
490e5c31af7Sopenharmony_ci				<< value.value
491e5c31af7Sopenharmony_ci				<< Writer::EndElement;
492e5c31af7Sopenharmony_ci			break;
493e5c31af7Sopenharmony_ci		}
494e5c31af7Sopenharmony_ci
495e5c31af7Sopenharmony_ci		default:
496e5c31af7Sopenharmony_ci			XE_FAIL("Unsupported result item");
497e5c31af7Sopenharmony_ci	}
498e5c31af7Sopenharmony_ci}
499e5c31af7Sopenharmony_ci
500e5c31af7Sopenharmony_civoid writeTestResult (const TestCaseResult& result, xe::xml::Writer& xmlWriter)
501e5c31af7Sopenharmony_ci{
502e5c31af7Sopenharmony_ci	using xml::Writer;
503e5c31af7Sopenharmony_ci
504e5c31af7Sopenharmony_ci	xmlWriter << Writer::BeginElement("TestCaseResult")
505e5c31af7Sopenharmony_ci			  << Writer::Attribute("Version", result.caseVersion)
506e5c31af7Sopenharmony_ci			  << Writer::Attribute("CasePath", result.casePath)
507e5c31af7Sopenharmony_ci			  << Writer::Attribute("CaseType", getTestCaseTypeName(result.caseType));
508e5c31af7Sopenharmony_ci
509e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < result.resultItems.getNumItems(); ndx++)
510e5c31af7Sopenharmony_ci		writeResultItem(result.resultItems.getItem(ndx), xmlWriter);
511e5c31af7Sopenharmony_ci
512e5c31af7Sopenharmony_ci	// Result item is not logged until end.
513e5c31af7Sopenharmony_ci	xmlWriter << Writer::BeginElement("Result")
514e5c31af7Sopenharmony_ci			  << Writer::Attribute("StatusCode", getTestStatusCodeName(result.statusCode))
515e5c31af7Sopenharmony_ci			  << result.statusDetails
516e5c31af7Sopenharmony_ci			  << Writer::EndElement;
517e5c31af7Sopenharmony_ci
518e5c31af7Sopenharmony_ci	xmlWriter << Writer::EndElement;
519e5c31af7Sopenharmony_ci}
520e5c31af7Sopenharmony_ci
521e5c31af7Sopenharmony_civoid writeTestResult (const TestCaseResult& result, std::ostream& stream)
522e5c31af7Sopenharmony_ci{
523e5c31af7Sopenharmony_ci	xml::Writer xmlWriter(stream);
524e5c31af7Sopenharmony_ci	stream << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
525e5c31af7Sopenharmony_ci	writeTestResult(result, xmlWriter);
526e5c31af7Sopenharmony_ci}
527e5c31af7Sopenharmony_ci
528e5c31af7Sopenharmony_civoid writeTestResultToFile (const TestCaseResult& result, const char* filename)
529e5c31af7Sopenharmony_ci{
530e5c31af7Sopenharmony_ci	std::ofstream str(filename, std::ofstream::binary|std::ofstream::trunc);
531e5c31af7Sopenharmony_ci	writeTestResult(result, str);
532e5c31af7Sopenharmony_ci	str.close();
533e5c31af7Sopenharmony_ci}
534e5c31af7Sopenharmony_ci
535e5c31af7Sopenharmony_ci} // xe
536