[libcamera-devel] [PATCH v9 3/3] tests: Test IPA serializer generation

Laurent Pinchart laurent.pinchart at ideasonboard.com
Tue Mar 2 02:18:45 CET 2021


Hi Paul,

On Tue, Mar 02, 2021 at 10:13:16AM +0900, paul.elder at ideasonboard.com wrote:
> On Tue, Mar 02, 2021 at 03:01:36AM +0200, Laurent Pinchart wrote:
> > On Mon, Mar 01, 2021 at 03:52:26PM +0900, Paul Elder wrote:
> > > Add a test to confirm that serializer and header generation works
> > > properly for mojom definition files, and that the serializer works
> > > properly.
> > > 
> > > Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
> > > Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> > > 
> > > ---
> > > Changes in v9:
> > > - rename everything vimc to test
> > > - add std:: to vectors and ties
> > > 
> > > No change in v8
> > > 
> > > Changes in v7:
> > > - add test to test serdes of a vector of *generated* structs
> > > 
> > > Changes in v6:
> > > - use namespacing in the mojom file, and in the test
> > > - add the enum to the test mojom file, as vimc.h no longer exists
> > > 
> > > Changes in v5:
> > > - add dummy event to event interface
> > > 
> > > New in v4
> > > ---
> > >  .../generated_serializer_test.cpp             | 156 ++++++++++++++++++
> > >  .../libcamera/ipa/test_ipa_interface.h        |   0
> > >  .../generated_serializer/meson.build          |  52 ++++++
> > >  .../generated_serializer/test.mojom           |  33 ++++
> > >  test/serialization/meson.build                |   2 +
> > >  5 files changed, 243 insertions(+)
> > >  create mode 100644 test/serialization/generated_serializer/generated_serializer_test.cpp
> > >  create mode 100644 test/serialization/generated_serializer/include/libcamera/ipa/test_ipa_interface.h
> > >  create mode 100644 test/serialization/generated_serializer/meson.build
> > >  create mode 100644 test/serialization/generated_serializer/test.mojom
> > > 
> > > diff --git a/test/serialization/generated_serializer/generated_serializer_test.cpp b/test/serialization/generated_serializer/generated_serializer_test.cpp
> > > new file mode 100644
> > > index 00000000..698c81d6
> > > --- /dev/null
> > > +++ b/test/serialization/generated_serializer/generated_serializer_test.cpp
> > > @@ -0,0 +1,156 @@
> > > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > > +/*
> > > + * Copyright (C) 2020, Google Inc.
> > > + *
> > > + * generated_serializer_test.cpp - Test generated serializer
> > > + */
> > > +
> > > +#include <algorithm>
> > > +#include <tuple>
> > > +#include <vector>
> > > +
> > > +#include "test.h"
> > > +
> > > +#include "test_ipa_interface.h"
> > > +#include "test_ipa_serializer.h"
> > > +
> > > +using namespace std;
> > > +using namespace libcamera;
> > > +
> > > +class IPAGeneratedSerializerTest : public Test
> > > +{
> > > +protected:
> > > +	int init() override
> > > +	{
> > > +		return TestPass;
> > > +	}
> > > +
> > > +	int run() override
> > > +	{
> > > +
> > > +#define TEST_FIELD_EQUALITY(struct1, struct2, field)		\
> > > +if (struct1.field != struct2.field) {				\
> > > +	cerr << #field << " field incorrect: expected \""	\
> > > +	     << t.field << "\", got \"" << u.field << "\"" << endl;\
> > > +	return TestFail;					\
> > > +}
> > > +
> > > +		ipa::test::TestStruct t, u;
> > > +
> > > +		t.m = {
> > > +			{ "a", "z" },
> > > +			{ "b", "z" },
> > > +			{ "c", "z" },
> > > +			{ "d", "z" },
> > > +			{ "e", "z" },
> > > +		};
> > > +
> > > +		t.a = { "a", "b", "c", "d", "e" };
> > > +
> > > +		t.s1 = "hello world";
> > > +		t.s2 = "goodbye";
> > > +		t.s3 = "lorem ipsum";
> > > +		t.i  = 58527;
> > > +
> > > +		std::vector<uint8_t> serialized;
> > > +
> > > +		std::tie(serialized, ignore) =
> > > +			IPADataSerializer<ipa::test::TestStruct>::serialize(t);
> > > +
> > > +		u = IPADataSerializer<ipa::test::TestStruct>::deserialize(serialized);
> > > +
> > > +		if (!equals(t.m, u.m))
> > > +			return TestFail;
> > > +
> > > +		if (!equals(t.a, u.a))
> > > +			return TestFail;
> > > +
> > > +		TEST_FIELD_EQUALITY(t, u, s1);
> > > +		TEST_FIELD_EQUALITY(t, u, s2);
> > > +		TEST_FIELD_EQUALITY(t, u, s3);
> > > +		TEST_FIELD_EQUALITY(t, u, i);
> > > +
> > > +
> > > +		/* Test vector of generated structs */
> > > +		std::vector<ipa::test::TestStruct> v = { t, u };
> > > +		std::vector<ipa::test::TestStruct> w;
> > > +
> > > +		std::tie(serialized, ignore) =
> > > +			IPADataSerializer<vector<ipa::test::TestStruct>>::serialize(v);
> > > +
> > > +		w = IPADataSerializer<vector<ipa::test::TestStruct>>::deserialize(serialized);
> > > +
> > > +		if (!equals(v[0].m, w[0].m) ||
> > > +		    !equals(v[1].m, w[1].m))
> > > +			return TestFail;
> > > +
> > > +		if (!equals(v[0].a, w[0].a) ||
> > > +		    !equals(v[1].a, w[1].a))
> > > +			return TestFail;
> > > +
> > > +		TEST_FIELD_EQUALITY(v[0], w[0], s1);
> > > +		TEST_FIELD_EQUALITY(v[0], w[0], s2);
> > > +		TEST_FIELD_EQUALITY(v[0], w[0], s3);
> > > +		TEST_FIELD_EQUALITY(v[0], w[0], i);
> > > +
> > > +		TEST_FIELD_EQUALITY(v[1], w[1], s1);
> > > +		TEST_FIELD_EQUALITY(v[1], w[1], s2);
> > > +		TEST_FIELD_EQUALITY(v[1], w[1], s3);
> > > +		TEST_FIELD_EQUALITY(v[1], w[1], i);
> > > +
> > > +		return TestPass;
> > > +	}
> > > +
> > > +private:
> > > +	bool equals(const map<string, string> &lhs, const map<string, string> &rhs)
> > > +	{
> > > +		bool eq = lhs.size() == rhs.size() &&
> > > +			  equal(lhs.begin(), lhs.end(), rhs.begin(),
> > > +				[](auto &a, auto &b) { return a.first == b.first &&
> > > +							      a.second == b.second; });
> > > +
> > > +		if (eq)
> > > +			return true;
> > > +
> > > +		cerr << "lhs:" << endl;
> > > +		for (const auto &pair : lhs)
> > > +			cerr << "- " << pair.first << ": "
> > > +			     << pair.second << endl;
> > > +
> > > +		cerr << "rhs:" << endl;
> > > +		for (const auto &pair : rhs)
> > > +			cerr << "- " << pair.first << ": "
> > > +			     << pair.second << endl;
> > > +
> > > +		return false;
> > > +	}
> > > +
> > > +	bool equals(const vector<string> &lhs, const vector<string> &rhs)
> > > +	{
> > > +		bool eq = lhs.size() == rhs.size();
> > > +
> > > +		if (!eq) {
> > > +			cerr << "sizes not equal" << endl;
> > > +			return false;
> > > +		}
> > > +
> > > +		for (unsigned int i = 0; i < lhs.size(); i++)
> > > +			if (lhs[i] != rhs[i])
> > > +				eq = false;
> > > +
> > > +		if (eq)
> > > +			return true;
> > > +
> > > +		cerr << "lhs:" << endl;
> > > +		for (const auto &str : lhs)
> > > +			cerr << "- " << str << endl;
> > > +
> > > +		cerr << "rhs:" << endl;
> > > +		for (const auto &str : rhs)
> > > +			cerr << "- " << str << endl;
> > > +
> > > +		return false;
> > > +	}
> > > +};
> > > +
> > > +TEST_REGISTER(IPAGeneratedSerializerTest)
> > > diff --git a/test/serialization/generated_serializer/include/libcamera/ipa/test_ipa_interface.h b/test/serialization/generated_serializer/include/libcamera/ipa/test_ipa_interface.h
> > > new file mode 100644
> > > index 00000000..e69de29b
> > 
> > Did you mean to add an empty test_ipa_interface.h ?
> 
> Yes, I did.
> 
> We tell the generator to generate a test_ipa_serializer.h based on
> test.mojom, but this generates #include
> <libcamera/test_ipa_interface.h>.

Ah good point.

> Although, below I generate test_ipa_interface.h from test.mojom.
> 
> Maybe it's better to mkdir -p
> test/serialization/generated_serializer/include/libcamera/ipa and then
> put the mojom file and the meson generator there?

If it's easy, sure. Otherwise, the empty header is fine, with a comment
in the file to explain what it's for.

> > > diff --git a/test/serialization/generated_serializer/meson.build b/test/serialization/generated_serializer/meson.build
> > > new file mode 100644
> > > index 00000000..aad6c4a1
> > > --- /dev/null
> > > +++ b/test/serialization/generated_serializer/meson.build
> > > @@ -0,0 +1,52 @@
> > > +# SPDX-License-Identifier: CC0-1.0
> > > +
> > > +# vimc.mojom-module
> 
> Oh I need to s/vimc/test here and below.
> 
> > > +mojom = custom_target('test_mojom_module',
> > > +                      input : 'test.mojom',
> > > +                      output : 'test.mojom-module',
> > > +                      command : [
> > > +                          mojom_parser,
> > > +                          '--output-root', meson.build_root(),
> > > +                          '--input-root', meson.source_root(),
> > > +                          '--mojoms', '@INPUT@'
> > > +                      ])
> > > +
> > > +# vimc_test_ipa_interface.h
> > > +header = custom_target('test_ipa_interface_h',
> > > +                       input : mojom,
> > > +                       output : 'test_ipa_interface.h',
> > > +                       depends : mojom_templates,
> > > +                       command : [
> > > +                           mojom_generator, 'generate',
> > > +                           '-g', 'libcamera',
> > > +                           '--bytecode_path', mojom_templates_dir,
> > > +                           '--libcamera_generate_header',
> > > +                           '--libcamera_output_path=@OUTPUT@',
> > > +                           './' +'@INPUT@'
> > > +                       ])
> > > +
> > > +# vimc_test_ipa_serializer.h
> > > +serializer = custom_target('test_ipa_serializer_h',
> > > +                           input : mojom,
> > > +                           output : 'test_ipa_serializer.h',
> > > +                           depends : mojom_templates,
> > > +                           command : [
> > > +                               mojom_generator, 'generate',
> > > +                               '-g', 'libcamera',
> > > +                               '--bytecode_path', mojom_templates_dir,
> > > +                               '--libcamera_generate_serializer',
> > > +                               '--libcamera_output_path=@OUTPUT@',
> > > +                               './' +'@INPUT@'
> > > +                           ])
> > > +
> > > +exe = executable('generated_serializer_test',
> > > +                 ['generated_serializer_test.cpp', header, serializer],
> > > +                 dependencies : libcamera_dep,
> > > +                 link_with : test_libraries,
> > > +                 include_directories : [
> > > +                     test_includes_internal,
> > > +                     './include',
> > > +                 ])
> > > +
> > > +test('generated_serializer_test', exe,
> > > +     suite : 'generated_serializer', is_parallel : false)
> > > diff --git a/test/serialization/generated_serializer/test.mojom b/test/serialization/generated_serializer/test.mojom
> > > new file mode 100644
> > > index 00000000..2fd973e9
> > > --- /dev/null
> > > +++ b/test/serialization/generated_serializer/test.mojom
> > > @@ -0,0 +1,33 @@
> > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> > > +
> > > +module ipa.test;
> > > +
> > > +enum IPAOperationCode {
> > > +	IPAOperationNone,
> > > +	IPAOperationInit,
> > > +	IPAOperationStart,
> > > +	IPAOperationStop,
> > > +};
> > > +
> > > +struct IPASettings {};
> > > +
> > > +struct TestStruct {
> > > +	map<string, string> m;
> > > +	array<string> a;
> > > +	string s1;
> > > +	string s2;
> > > +	int32 i;
> > > +	string s3;
> > > +};
> > > +
> > > +interface IPAVimcInterface {
> > > +	init(IPASettings settings) => (int32 ret);
> > > +	start() => (int32 ret);
> > > +	stop();
> > > +
> > > +	test(TestStruct s);
> > > +};
> 
> Oh I forgot to s/Vimc/Test here and below too.
> 
> > > +
> > > +interface IPAVimcEventInterface {
> > > +	dummyEvent(uint32 val);
> > > +};
> > > diff --git a/test/serialization/meson.build b/test/serialization/meson.build
> > > index a4636337..60ebf325 100644
> > > --- a/test/serialization/meson.build
> > > +++ b/test/serialization/meson.build
> > > @@ -1,5 +1,7 @@
> > >  # SPDX-License-Identifier: CC0-1.0
> > >  
> > > +subdir('generated_serializer')
> > > +
> > >  serialization_tests = [
> > >      ['control_serialization',     'control_serialization.cpp'],
> > >      ['ipa_data_serializer_test',  'ipa_data_serializer_test.cpp'],

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list