.NET Bindings: Add DotnetTest class to gbuild

This commit adds the DotnetTest gbuild class to build a unit test
suite using the .NET SDK and the NUnit testing framework.

Also adds a DotnetTest target for the net_ure module, with unit tests
for the Any type, as well as some minor changes to the Any type that
came about when writing the test cases.

Change-Id: Idbc08ac8f0736dd7355092dd1e69a5f1b4137c4c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168956
Tested-by: Jenkins
Reviewed-by: Hossein <hossein@libreoffice.org>
This commit is contained in:
RMZeroFour 2024-07-27 20:06:56 +05:30 committed by Hossein
parent eca8414763
commit e8a8d32fb3
9 changed files with 284 additions and 2 deletions

View file

@ -138,6 +138,7 @@ gbuild_TARGETS := AllLangHelp \
CustomTarget \
Dictionary \
DotnetLibrary \
DotnetTest \
Executable \
Extension \
ExtensionPackage \

View file

@ -0,0 +1,17 @@
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
$(eval $(call gb_DotnetTest_DotnetTest,net_basetypes_tests,$(gb_DotnetTest_CS)))
$(eval $(call gb_DotnetTest_add_sources,net_basetypes_tests,\
net_ure/qa/basetypes/AnyTests \
))
$(eval $(call gb_DotnetTest_link_library,net_basetypes_tests,net_basetypes))
# vim: set noet sw=4 ts=4:

View file

@ -19,6 +19,10 @@ $(eval $(call gb_Module_add_targets,net_ure,\
Package_net_uretypes \
Package_net_oootypes \
))
$(eval $(call gb_Module_add_subsequentcheck_targets,net_ure,\
DotnetTest_net_basetypes_tests \
))
endif
# vim: set noet sw=4 ts=4:

View file

@ -0,0 +1,100 @@
using NUnit.Framework;
using com.sun.star.uno;
[TestFixture]
public class AnyTests
{
[Test]
[Description("Tests if Any.VOID has a null value and type as void")]
public void VOID_HasNullValueAndVoidType()
{
Assert.That(Any.VOID, Is.Not.Null);
Assert.That(Any.VOID.Value, Is.Null);
Assert.That(Any.VOID.Type, Is.EqualTo(typeof(void)));
}
[Test]
[Description("Tests if the Any(type, value) constructor throws on invalid args")]
public void ctor_RejectsInvalidParams()
{
Assert.That(() => new Any(null, 10), Throws.ArgumentNullException);
Assert.That(() => new Any(typeof(Any), Any.VOID), Throws.ArgumentException);
Assert.That(() => new Any(typeof(int), null), Throws.ArgumentException);
}
[Test]
[Description("Tests if Any.with<T>(value) throws on invalid args")]
public void with_RejectsInvalidParams()
{
Assert.That(() => new Any(typeof(Any), Any.VOID), Throws.ArgumentException);
}
[Test]
[Description("Tests if Any.equals(other) and Any.operator== returns true for identical values")]
public void equals_ReturnsTrueForSame()
{
Assert.That(Any.VOID == new Any(typeof(void), null), Is.True);
Assert.That(Any.with(10).equals(new Any(typeof(int), 10)), Is.True);
Assert.That(new Any(typeof(bool), false).Equals(Any.with(false)), Is.True);
}
[Test]
[Description("Tests if Any.equals(other) and Any.operator== returns false for different values")]
public void equals_ReturnsTrueForDifferent()
{
Assert.That(Any.VOID == Any.with(10), Is.False);
Assert.That(Any.VOID != Any.with(10), Is.True);
Assert.That(Any.with(10).equals(Any.with(20)), Is.False);
Assert.That(Any.with(true).Equals(Any.with(1)), Is.False);
}
[Test]
[Description("Tests if Any.hasValue() returns false for Any.VOID and true for all else")]
public void hasValue_ReturnsFalseOnlyForVOID()
{
Assert.That(Any.VOID.hasValue, Is.False);
Assert.That(Any.with(10).hasValue, Is.True);
Assert.That(new Any(typeof(string), "hello").hasValue, Is.True);
}
[Test]
[Description("Tests if Any.setValue(type, value) method updates type and value correctly")]
public void setValue_UpdatesTypeAndValue()
{
Any any = new Any(typeof(int), 10);
Assert.That(any.Type, Is.EqualTo(typeof(int)));
Assert.That(any.Value, Is.EqualTo(10));
any.setValue(typeof(string), "hello");
Assert.That(any.Type, Is.EqualTo(typeof(string)));
Assert.That(any.Value, Is.EqualTo("hello"));
any.setValue(false);
Assert.That(any.Type, Is.EqualTo(typeof(bool)));
Assert.That(any.Value, Is.EqualTo(false));
}
[Test]
[Description("Tests if Any.setValue(type, value) method throws on invalid args")]
public void setValue_RejectsInvalidParams()
{
Any any = Any.with(10);
Assert.That(() => any.setValue(null, 10), Throws.ArgumentNullException);
Assert.That(() => any.setValue(Any.VOID), Throws.ArgumentException);
Assert.That(() => any.setValue(typeof(int), null), Throws.ArgumentException);
}
[Test]
[Description("Tests if Any.GetHashCode() returns same hash for identical values")]
public void GetHashCode_ReturnsTrueForSame()
{
Assert.That(Any.VOID.GetHashCode() == Any.VOID.GetHashCode(), Is.True);
Assert.That(Any.with(10).GetHashCode() == Any.with(10).GetHashCode(), Is.True);
}
[Test]
[Description("Tests if Any.GetHashCode() returns different hash for different values")]
public void GetHashCode_ReturnsTrueForDifferent()
{
Assert.That(Any.VOID.GetHashCode() == Any.with(10).GetHashCode(), Is.False);
}
}

View file

@ -37,11 +37,20 @@ namespace com.sun.star.uno
Type = type;
Value = value;
}
public void setValue<T>(T value) => setValue(typeof(T), value);
public bool equals(Any obj) => Type == obj.Type && Value == obj.Value;
public bool equals(Any other)
{
return other != null && Type.Equals(other.Type)
&& (Value == null ? other.Value == null : Value.Equals(other.Value));
}
public override bool Equals(object obj) => (obj is Any other) && equals(other);
public static bool operator ==(Any left, Any right) => left?.Equals(right) ?? false;
public static bool operator !=(Any left, Any right) => !(left == right);
public override bool Equals(object obj) => obj is Any other && equals(other);
public override int GetHashCode() => (Type, Value).GetHashCode();
public override string ToString() => $"uno.Any {{ Type = {Type}, Value = {Value ?? "Null"} }}";
}
}

146
solenv/gbuild/DotnetTest.mk Normal file
View file

@ -0,0 +1,146 @@
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
###########################
# DotnetTest Target Class #
###########################
####### Constant Strings #########
gb_DotnetTest_CS := cs
gb_DotnetTest_FS := fs
gb_DotnetTest_VB := vb
define gb_DotnetTest__TEST_NUGETS
<PackageReference Include="NUnit" Version="4.1.0" /> \
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" /> \
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" /> \
endef
####### Build and Clean Targets #########
# Template for a target to generate the project file for a DotnetTest
define gb_DotnetTest__project_target
$$(gb_DotnetTest_$(1)_project) :
$$(shell mkdir -p $$(dir $$@))
$$(file >$$@,<Project Sdk="Microsoft.NET.Sdk">)
$$(file >>$$@,<PropertyGroup>)
$$(file >>$$@,$$(DOTNET_PROPERTY_ELEMENTS))
$$(file >>$$@,</PropertyGroup>)
$$(file >>$$@,<ItemGroup>)
$$(file >>$$@,$$(DOTNET_ITEM_ELEMENTS))
$$(file >>$$@,</ItemGroup>)
$$(file >>$$@,</Project>)
endef
# Template for a target to build and run a DotnetTest
define gb_DotnetTest__build_target
$$(call gb_DotnetTest_get_target,$(1)) : $$(gb_DotnetTest_$(1)_project)
$$(call gb_Output_announce,$(1),$(true),NET,4)
$$(call gb_Trace_StartRange,$(1),NET)
$$(call gb_Helper_abbreviate_dirs,\
$$(call gb_Helper_print_on_error,\
"$$(DOTNET)" test $$< $$(DOTNET_BUILD_FLAGS) -o $$(dir $$@),\
$$(gb_DotnetTest_workdir)/$(1)/log))
$$(call gb_Trace_EndRange,$(1),NET)
endef
# Template for a target to clean a DotnetTest
define gb_DotnetTest__clean_target
$$(call gb_DotnetTest_get_clean_target,$(1)) :
$$(call gb_Output_announce,$(1),$(false),NET,4)
$$(call gb_Helper_abbreviate_dirs,\
rm -rf $$(gb_DotnetTest_$(1)_project))
endef
####### Test Target Constructor #########
# Generates one test project for the given language, instantiating
# the project file, build/run and clean targets from above templates
# call gb_DotnetTest_DotnetTest,targetname,language
define gb_DotnetTest_DotnetTest
gb_DotnetTest_$(1)_language := $(2)
gb_DotnetTest_$(1)_project := $(gb_DotnetTest_workdir)/$(1)/$(1).$(2)proj
$$(gb_DotnetTest_$(1)_project) : DOTNET_PROPERTY_ELEMENTS := <TargetFramework>net8.0</TargetFramework>
$$(gb_DotnetTest_$(1)_project) : DOTNET_PROPERTY_ELEMENTS += <IsPackable>false</IsPackable>
$$(gb_DotnetTest_$(1)_project) : DOTNET_PROPERTY_ELEMENTS += <IsTestProject>true</IsTestProject>
$$(gb_DotnetTest_$(1)_project) : DOTNET_PROPERTY_ELEMENTS += <AssemblyName>$(1)</AssemblyName>
$$(gb_DotnetTest_$(1)_project) : DOTNET_ITEM_ELEMENTS := $(gb_DotnetTest__TEST_NUGETS)
$$(eval $$(call gb_DotnetTest__project_target,$(1)))
$$(call gb_DotnetTest_get_target,$(1)) : DOTNET_BUILD_FLAGS := $(if $(ENABLE_DEBUG),-c Debug,-c Release)
.PHONY : $$(call gb_DotnetTest_get_target,$(1))
$$(eval $$(call gb_DotnetTest__build_target,$(1)))
.PHONY : $$(call gb_DotnetTest_get_clean_target,$(1))
$$(eval $$(call gb_DotnetTest__clean_target,$(1)))
$$(eval $$(call gb_Module_register_target, \
$(call gb_DotnetTest_get_target,$(1)), \
$(call gb_DotnetTest_get_clean_target,$(1))))
$(call gb_Helper_make_userfriendly_targets,$(1),DotnetTest)
endef
####### Target Property Setters #########
# Add flags used for compilation
# call gb_DotnetTest_add_build_flags,target,flags
define gb_DotnetTest_add_build_flags
$(call gb_DotnetTest_get_target,$(1)) : DOTNET_BUILD_FLAGS += $(2)
endef
# Add <PropertyGroup> elements to the project file
# call gb_DotnetTest_add_properties,target,properties
define gb_DotnetTest_add_properties
$(gb_DotnetTest_$(1)_project) : DOTNET_PROPERTY_ELEMENTS += $(2)
endef
# Add <ItemGroup> elements to the project file
# call gb_DotnetTest_add_items,target,items
define gb_DotnetTest_add_items
$(gb_DotnetTest_$(1)_project) : DOTNET_ITEM_ELEMENTS += $(2)
endef
# Add one source file to the project file
# This adds it to the project, and makes it a build dependency
# so the test is rebuilt if the source changes
# call gb_DotnetTest_add_source,target,source
define gb_DotnetTest_add_source
$(gb_DotnetTest_$(1)_project) : $(SRCDIR)/$(2).$(gb_DotnetTest_$(1)_language)
$(call gb_DotnetTest_add_items,$(1),<Compile Include="$(SRCDIR)/$(2).$(gb_DotnetTest_$(1)_language)"/>)
endef
# Add source files to the project file
# This adds them to the project, and makes it them build dependency
# so the test is rebuilt if the sources change
# call gb_DotnetTest_add_sources,target,sources
define gb_DotnetTest_add_sources
$(foreach source,$(2),$(call gb_DotnetTest_add_source,$(1),$(source)))
endef
# Link to a DotnetLibrary target
# call gb_DotnetTest_link_library,target,library
define gb_DotnetTest_link_library
$(gb_DotnetTest_$(1)_project) : $(call gb_DotnetLibrary_get_target,$(2))
$(call gb_DotnetTest_add_items,$(1),<ProjectReference Include="$(gb_DotnetLibrary_$(2)_project)"/>)
endef
# vim: set noet sw=4 ts=4:

View file

@ -65,6 +65,8 @@ gb_CxxObject_get_target = $(WORKDIR)/CxxObject/$(1).o
gb_CxxObject_get_dwo_target = $(WORKDIR)/CxxObject/$(1).dwo
gb_DotnetLibrary_get_target = $(WORKDIR)/DotnetLibrary/$(1)/$(1).dll
gb_DotnetLibrary_workdir = $(WORKDIR)/DotnetLibrary
gb_DotnetTest_get_target = $(WORKDIR)/DotnetTest/$(1)/done
gb_DotnetTest_workdir = $(WORKDIR)/DotnetTest
gb_GenCxxObject_get_target = $(WORKDIR)/GenCxxObject/$(1).o
gb_GenCxxObject_get_dwo_target = $(WORKDIR)/GenCxxObject/$(1).dwo
gb_GenAsmObject_get_target = $(WORKDIR)/GenAsmObject/$(1).o
@ -276,6 +278,7 @@ $(eval $(call gb_Helper_make_clean_targets,\
DescriptionTranslateTarget \
Dictionary \
DotnetLibrary \
DotnetTest \
Executable \
ExternalPackage \
Extension \

View file

@ -83,6 +83,7 @@ AVAILABLE TARGETS
o CustomTarget
o Dictionary
o DotnetLibrary
o DotnetTest
o Executable
o Extension
o ExternalPackage

View file

@ -331,6 +331,7 @@ include $(foreach class, \
CliNativeLibrary \
CliUnoApi \
DotnetLibrary \
DotnetTest \
Zip \
AllLangPackage \
Configuration \