/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2018, Google Inc.
 *
 * byte_stream_buffer.cpp - ByteStreamBuffer tests
 */

#include <array>
#include <iostream>

#include "libcamera/internal/byte_stream_buffer.h"

#include "test.h"

using namespace std;
using namespace libcamera;

class ByteStreamBufferTest : public Test
{
protected:
	int run()
	{
		/*
		 * gcc 11.1.0 incorrectly raises a maybe-uninitialized warning
		 * when calling data.size() below (if the address sanitizer is
		 * disabled). Silence it by initializing the array.
		 */
		std::array<uint8_t, 100> data = {};
		unsigned int i;
		uint32_t value;
		int ret;

		/*
		 * Write mode.
		 */
		ByteStreamBuffer wbuf(data.data(), data.size());

		if (wbuf.base() != data.data() || wbuf.size() != data.size() ||
		    wbuf.offset() != 0 || wbuf.overflow()) {
			cerr << "Write buffer incorrectly constructed" << endl;
			return TestFail;
		}

		/* Test write. */
		value = 0x12345678;
		ret = wbuf.write(&value);
		if (ret || wbuf.offset() != 4 || wbuf.overflow() ||
		    *reinterpret_cast<uint32_t *>(data.data()) != 0x12345678) {
			cerr << "Write failed on write buffer" << endl;
			return TestFail;
		}

		/* Test write carve out. */
		ByteStreamBuffer wco = wbuf.carveOut(10);
		if (wco.base() != wbuf.base() + 4 || wco.size() != 10 ||
		    wco.offset() != 0 || wco.overflow() || wbuf.offset() != 14 ||
		    wbuf.overflow()) {
			cerr << "Carving out write buffer failed" << endl;
			return TestFail;
		}

		/* Test write on the carved out buffer. */
		value = 0x87654321;
		ret = wco.write(&value);
		if (ret || wco.offset() != 4 || wco.overflow() ||
		    *reinterpret_cast<uint32_t *>(data.data() + 4) != 0x87654321) {
			cerr << "Write failed on carve out buffer" << endl;
			return TestFail;
		}

		if (wbuf.offset() != 14 || wbuf.overflow()) {
			cerr << "Write on carve out buffer modified write buffer" << endl;
			return TestFail;
		}

		/* Test read, this should fail. */
		ret = wbuf.read(&value);
		if (!ret || wbuf.overflow()) {
			cerr << "Read should fail on write buffer" << endl;
			return TestFail;
		}

		/* Test overflow on carved out buffer. */
		for (i = 0; i < 2; ++i) {
			ret = wco.write(&value);
			if (ret < 0)
				break;
		}

		if (i != 1 || !wco.overflow() || !wbuf.overflow()) {
			cerr << "Write on carve out buffer failed to overflow" << endl;
			return TestFail;
		}

		/* Test reinitialization of the buffer. */
		wbuf = ByteStreamBuffer(data.data(), data.size());
		if (wbuf.overflow() || wbuf.base() != data.data() ||
		    wbuf.offset() != 0) {
			cerr << "Write buffer reinitialization failed" << endl;
			return TestFail;
		}

		/*
		 * Read mode.
		 */
		ByteStreamBuffer rbuf(const_cast<const uint8_t *>(data.data()),
				      data.size());

		if (rbuf.base() != data.data() || rbuf.size() != data.size() ||
		    rbuf.offset() != 0 || rbuf.overflow()) {
			cerr << "Read buffer incorrectly constructed" << endl;
			return TestFail;
		}

		/* Test read. */
		value = 0;
		ret = rbuf.read(&value);
		if (ret || rbuf.offset() != 4 || rbuf.overflow() ||
		    value != 0x12345678) {
			cerr << "Write failed on write buffer" << endl;
			return TestFail;
		}

		/* Test read carve out. */
		ByteStreamBuffer rco = rbuf.carveOut(10);
		if (rco.base() != rbuf.base() + 4 || rco.size() != 10 ||
		    rco.offset() != 0 || rco.overflow() || rbuf.offset() != 14 ||
		    rbuf.overflow()) {
			cerr << "Carving out read buffer failed" << endl;
			return TestFail;
		}

		/* Test read on the carved out buffer. */
		value = 0;
		ret = rco.read(&value);
		if (ret || rco.offset() != 4 || rco.overflow() || value != 0x87654321) {
			cerr << "Read failed on carve out buffer" << endl;
			return TestFail;
		}

		if (rbuf.offset() != 14 || rbuf.overflow()) {
			cerr << "Read on carve out buffer modified read buffer" << endl;
			return TestFail;
		}

		/* Test write, this should fail. */
		ret = rbuf.write(&value);
		if (!ret || rbuf.overflow()) {
			cerr << "Write should fail on read buffer" << endl;
			return TestFail;
		}

		/* Test overflow on carved out buffer. */
		for (i = 0; i < 2; ++i) {
			ret = rco.read(&value);
			if (ret < 0)
				break;
		}

		if (i != 1 || !rco.overflow() || !rbuf.overflow()) {
			cerr << "Read on carve out buffer failed to overflow" << endl;
			return TestFail;
		}

		/* Test reinitialization of the buffer. */
		rbuf = ByteStreamBuffer(const_cast<const uint8_t *>(data.data()),
					data.size());
		if (rbuf.overflow() || rbuf.base() != data.data() ||
		    rbuf.offset() != 0) {
			cerr << "Read buffer reinitialization failed" << endl;
			return TestFail;
		}

		return TestPass;
	}
};

TEST_REGISTER(ByteStreamBufferTest)
<a id='n44' href='#n44'>44</a>
<a id='n45' href='#n45'>45</a>
<a id='n46' href='#n46'>46</a>
<a id='n47' href='#n47'>47</a>
<a id='n48' href='#n48'>48</a>
<a id='n49' href='#n49'>49</a>
<a id='n50' href='#n50'>50</a>
<a id='n51' href='#n51'>51</a>
<a id='n52' href='#n52'>52</a>
<a id='n53' href='#n53'>53</a>
<a id='n54' href='#n54'>54</a>
<a id='n55' href='#n55'>55</a>
<a id='n56' href='#n56'>56</a>
<a id='n57' href='#n57'>57</a>
<a id='n58' href='#n58'>58</a>
<a id='n59' href='#n59'>59</a>
<a id='n60' href='#n60'>60</a>
<a id='n61' href='#n61'>61</a>
<a id='n62' href='#n62'>62</a>
<a id='n63' href='#n63'>63</a>
<a id='n64' href='#n64'>64</a>
<a id='n65' href='#n65'>65</a>
<a id='n66' href='#n66'>66</a>
<a id='n67' href='#n67'>67</a>
<a id='n68' href='#n68'>68</a>
<a id='n69' href='#n69'>69</a>
<a id='n70' href='#n70'>70</a>
<a id='n71' href='#n71'>71</a>
<a id='n72' href='#n72'>72</a>
<a id='n73' href='#n73'>73</a>
<a id='n74' href='#n74'>74</a>
<a id='n75' href='#n75'>75</a>
<a id='n76' href='#n76'>76</a>
<a id='n77' href='#n77'>77</a>
<a id='n78' href='#n78'>78</a>
<a id='n79' href='#n79'>79</a>
<a id='n80' href='#n80'>80</a>
<a id='n81' href='#n81'>81</a>
<a id='n82' href='#n82'>82</a>
<a id='n83' href='#n83'>83</a>
<a id='n84' href='#n84'>84</a>
<a id='n85' href='#n85'>85</a>
<a id='n86' href='#n86'>86</a>
<a id='n87' href='#n87'>87</a>
<a id='n88' href='#n88'>88</a>
<a id='n89' href='#n89'>89</a>
<a id='n90' href='#n90'>90</a>
<a id='n91' href='#n91'>91</a>
<a id='n92' href='#n92'>92</a>
<a id='n93' href='#n93'>93</a>
<a id='n94' href='#n94'>94</a>
<a id='n95' href='#n95'>95</a>
<a id='n96' href='#n96'>96</a>
<a id='n97' href='#n97'>97</a>
<a id='n98' href='#n98'>98</a>
<a id='n99' href='#n99'>99</a>
<a id='n100' href='#n100'>100</a>
<a id='n101' href='#n101'>101</a>
<a id='n102' href='#n102'>102</a>
</pre></td>
<td class='lines'><pre><code><span class="hl com">/* SPDX-License-Identifier: GPL-2.0-or-later */</span>
<span class="hl com">/*</span>
<span class="hl com"> * Copyright (C) 2019, Google Inc.</span>
<span class="hl com"> *</span>
<span class="hl com"> * libcamera V4L2 API tests</span>
<span class="hl com"> */</span>

<span class="hl ppc">#include &lt;iostream&gt;</span>

<span class="hl ppc">#include &lt;linux/media-bus-format.h&gt;</span>

<span class="hl ppc">#include</span> <span class="hl pps">&quot;v4l2_videodevice_test.h&quot;</span><span class="hl ppc"></span>

<span class="hl ppc">#include</span> <span class="hl pps">&quot;device_enumerator.h&quot;</span><span class="hl ppc"></span>
<span class="hl ppc">#include</span> <span class="hl pps">&quot;media_device.h&quot;</span><span class="hl ppc"></span>

<span class="hl kwa">using namespace</span> std<span class="hl opt">;</span>
<span class="hl kwa">using namespace</span> libcamera<span class="hl opt">;</span>

<span class="hl kwb">int</span> <span class="hl kwc">V4L2VideoDeviceTest</span><span class="hl opt">::</span><span class="hl kwd">init</span><span class="hl opt">()</span>
<span class="hl opt">{</span>
	enumerator_ <span class="hl opt">=</span> <span class="hl kwc">DeviceEnumerator</span><span class="hl opt">::</span><span class="hl kwd">create</span><span class="hl opt">();</span>
	<span class="hl kwa">if</span> <span class="hl opt">(!</span>enumerator_<span class="hl opt">) {</span>
		cerr <span class="hl opt">&lt;&lt;</span> <span class="hl str">&quot;Failed to create device enumerator&quot;</span> <span class="hl opt">&lt;&lt;</span> endl<span class="hl opt">;</span>
		<span class="hl kwa">return</span> TestFail<span class="hl opt">;</span>
	<span class="hl opt">}</span>

	<span class="hl kwa">if</span> <span class="hl opt">(</span>enumerator_<span class="hl opt">-&gt;</span><span class="hl kwd">enumerate</span><span class="hl opt">()) {</span>
		cerr <span class="hl opt">&lt;&lt;</span> <span class="hl str">&quot;Failed to enumerate media devices&quot;</span> <span class="hl opt">&lt;&lt;</span> endl<span class="hl opt">;</span>
		<span class="hl kwa">return</span> TestFail<span class="hl opt">;</span>
	<span class="hl opt">}</span>

	DeviceMatch <span class="hl kwd">dm</span><span class="hl opt">(</span>driver_<span class="hl opt">);</span>
	dm<span class="hl opt">.</span><span class="hl kwd">add</span><span class="hl opt">(</span>entity_<span class="hl opt">);</span>

	media_ <span class="hl opt">=</span> enumerator_<span class="hl opt">-&gt;</span><span class="hl kwd">search</span><span class="hl opt">(</span>dm<span class="hl opt">);</span>
	<span class="hl kwa">if</span> <span class="hl opt">(!</span>media_<span class="hl opt">)</span>
		<span class="hl kwa">return</span> TestSkip<span class="hl opt">;</span>

	MediaEntity <span class="hl opt">*</span>entity <span class="hl opt">=</span> media_<span class="hl opt">-&gt;</span><span class="hl kwd">getEntityByName</span><span class="hl opt">(</span>entity_<span class="hl opt">);</span>
	<span class="hl kwa">if</span> <span class="hl opt">(!</span>entity<span class="hl opt">)</span>
		<span class="hl kwa">return</span> TestSkip<span class="hl opt">;</span>

	capture_ <span class="hl opt">=</span> <span class="hl kwa">new</span> <span class="hl kwd">V4L2VideoDevice</span><span class="hl opt">(</span>entity<span class="hl opt">);</span>
	<span class="hl kwa">if</span> <span class="hl opt">(!</span>capture_<span class="hl opt">)</span>
		<span class="hl kwa">return</span> TestFail<span class="hl opt">;</span>

	<span class="hl kwa">if</span> <span class="hl opt">(!</span>media_<span class="hl opt">-&gt;</span><span class="hl kwd">acquire</span><span class="hl opt">())</span>
		<span class="hl kwa">return</span> TestFail<span class="hl opt">;</span>

	<span class="hl kwb">int</span> ret <span class="hl opt">=</span> media_<span class="hl opt">-&gt;</span><span class="hl kwd">disableLinks</span><span class="hl opt">();</span>
	media_<span class="hl opt">-&gt;</span><span class="hl kwd">release</span><span class="hl opt">();</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span>ret<span class="hl opt">)</span>
		<span class="hl kwa">return</span> TestFail<span class="hl opt">;</span>

	<span class="hl kwa">if</span> <span class="hl opt">(</span>capture_<span class="hl opt">-&gt;</span><span class="hl kwd">open</span><span class="hl opt">())</span>
		<span class="hl kwa">return</span> TestFail<span class="hl opt">;</span>

	V4L2DeviceFormat format <span class="hl opt">= {};</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span>capture_<span class="hl opt">-&gt;</span><span class="hl kwd">getFormat</span><span class="hl opt">(&amp;</span>format<span class="hl opt">))</span>
		<span class="hl kwa">return</span> TestFail<span class="hl opt">;</span>

	<span class="hl kwa">if</span> <span class="hl opt">(</span>driver_ <span class="hl opt">==</span> <span class="hl str">&quot;vimc&quot;</span><span class="hl opt">) {</span>
		sensor_ <span class="hl opt">=</span> <span class="hl kwa">new</span> <span class="hl kwd">CameraSensor</span><span class="hl opt">(</span>media_<span class="hl opt">-&gt;</span><span class="hl kwd">getEntityByName</span><span class="hl opt">(</span><span class="hl str">&quot;Sensor A&quot;</span><span class="hl opt">));</span>
		<span class="hl kwa">if</span> <span class="hl opt">(</span>sensor_<span class="hl opt">-&gt;</span><span class="hl kwd">init</span><span class="hl opt">())</span>
			<span class="hl kwa">return</span> TestFail<span class="hl opt">;</span>

		debayer_ <span class="hl opt">=</span> <span class="hl kwa">new</span> <span class="hl kwd">V4L2Subdevice</span><span class="hl opt">(</span>media_<span class="hl opt">-&gt;</span><span class="hl kwd">getEntityByName</span><span class="hl opt">(</span><span class="hl str">&quot;Debayer A&quot;</span><span class="hl opt">));</span>
		<span class="hl kwa">if</span> <span class="hl opt">(</span>debayer_<span class="hl opt">-&gt;</span><span class="hl kwd">open</span><span class="hl opt">())</span>
			<span class="hl kwa">return</span> TestFail<span class="hl opt">;</span>

		format<span class="hl opt">.</span>fourcc <span class="hl opt">=</span> V4L2_PIX_FMT_SBGGR8<span class="hl opt">;</span>

		V4L2SubdeviceFormat subformat <span class="hl opt">= {};</span>
		subformat<span class="hl opt">.</span>mbus_code <span class="hl opt">=</span> MEDIA_BUS_FMT_SBGGR8_1X8<span class="hl opt">;</span>
		subformat<span class="hl opt">.</span>size <span class="hl opt">=</span> format<span class="hl opt">.</span>size<span class="hl opt">;</span>

		<span class="hl kwa">if</span> <span class="hl opt">(</span>sensor_<span class="hl opt">-&gt;</span><span class="hl kwd">setFormat</span><span class="hl opt">(&amp;</span>subformat<span class="hl opt">))</span>
			<span class="hl kwa">return</span> TestFail<span class="hl opt">;</span>

		<span class="hl kwa">if</span> <span class="hl opt">(</span>debayer_<span class="hl opt">-&gt;</span><span class="hl kwd">setFormat</span><span class="hl opt">(</span><span class="hl num">0</span><span class="hl opt">, &amp;</span>subformat<span class="hl opt">))</span>
			<span class="hl kwa">return</span> TestFail<span class="hl opt">;</span>
	<span class="hl opt">}</span>

	format<span class="hl opt">.</span>size<span class="hl opt">.</span>width <span class="hl opt">=</span> <span class="hl num">640</span><span class="hl opt">;</span>
	format<span class="hl opt">.</span>size<span class="hl opt">.</span>height <span class="hl opt">=</span> <span class="hl num">480</span><span class="hl opt">;</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span>capture_<span class="hl opt">-&gt;</span><span class="hl kwd">setFormat</span><span class="hl opt">(&amp;</span>format<span class="hl opt">))</span>
		<span class="hl kwa">return</span> TestFail<span class="hl opt">;</span>

	<span class="hl kwa">return</span> TestPass<span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwb">void</span> <span class="hl kwc">V4L2VideoDeviceTest</span><span class="hl opt">::</span><span class="hl kwd">cleanup</span><span class="hl opt">()</span>
<span class="hl opt">{</span>
	capture_<span class="hl opt">-&gt;</span><span class="hl kwd">streamOff</span><span class="hl opt">();</span>
	capture_<span class="hl opt">-&gt;</span><span class="hl kwd">releaseBuffers</span><span class="hl opt">();</span>
	capture_<span class="hl opt">-&gt;</span><span class="hl kwd">close</span><span class="hl opt">();</span>

	<span class="hl kwa">delete</span> debayer_<span class="hl opt">;</span>
	<span class="hl kwa">delete</span> sensor_<span class="hl opt">;</span>
	<span class="hl kwa">delete</span> capture_<span class="hl opt">;</span>
<span class="hl opt">};</span>
</code></pre></td></tr></table>
</div> <!-- class=content -->
<div class='footer'>generated by <a href='https://git.zx2c4.com/cgit/about/'>cgit v1.2.1</a> (<a href='https://git-scm.com/'>git 2.18.0</a>) at 2025-03-04 04:58:24 +0000</div>
</div> <!-- id=cgit -->
</body>
</html>