From e8a8d32fb3cc8b1f8fc17788ab00dffff1f4a950 Mon Sep 17 00:00:00 2001 From: RMZeroFour Date: Sat, 27 Jul 2024 20:06:56 +0530 Subject: [PATCH] .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 --- Makefile.in | 1 + net_ure/DotnetTest_net_basetypes_tests.mk | 17 +++ net_ure/Module_net_ure.mk | 4 + net_ure/qa/basetypes/AnyTests.cs | 100 +++++++++++++++ net_ure/source/basetypes/Any.cs | 13 +- solenv/gbuild/DotnetTest.mk | 146 ++++++++++++++++++++++ solenv/gbuild/TargetLocations.mk | 3 + solenv/gbuild/gbuild.help.txt | 1 + solenv/gbuild/gbuild.mk | 1 + 9 files changed, 284 insertions(+), 2 deletions(-) create mode 100644 net_ure/DotnetTest_net_basetypes_tests.mk create mode 100644 net_ure/qa/basetypes/AnyTests.cs create mode 100644 solenv/gbuild/DotnetTest.mk diff --git a/Makefile.in b/Makefile.in index b2d59e3075ab..32ee72b2e099 100644 --- a/Makefile.in +++ b/Makefile.in @@ -138,6 +138,7 @@ gbuild_TARGETS := AllLangHelp \ CustomTarget \ Dictionary \ DotnetLibrary \ + DotnetTest \ Executable \ Extension \ ExtensionPackage \ diff --git a/net_ure/DotnetTest_net_basetypes_tests.mk b/net_ure/DotnetTest_net_basetypes_tests.mk new file mode 100644 index 000000000000..3a2406a859dc --- /dev/null +++ b/net_ure/DotnetTest_net_basetypes_tests.mk @@ -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: diff --git a/net_ure/Module_net_ure.mk b/net_ure/Module_net_ure.mk index 98e3a80505e3..e5bf692114f4 100644 --- a/net_ure/Module_net_ure.mk +++ b/net_ure/Module_net_ure.mk @@ -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: diff --git a/net_ure/qa/basetypes/AnyTests.cs b/net_ure/qa/basetypes/AnyTests.cs new file mode 100644 index 000000000000..cee504a1744f --- /dev/null +++ b/net_ure/qa/basetypes/AnyTests.cs @@ -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(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); + } +} diff --git a/net_ure/source/basetypes/Any.cs b/net_ure/source/basetypes/Any.cs index 163bc59de631..7f4a8580b019 100644 --- a/net_ure/source/basetypes/Any.cs +++ b/net_ure/source/basetypes/Any.cs @@ -37,11 +37,20 @@ namespace com.sun.star.uno Type = type; Value = value; } + public void setValue(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"} }}"; } } diff --git a/solenv/gbuild/DotnetTest.mk b/solenv/gbuild/DotnetTest.mk new file mode 100644 index 000000000000..c51487cecf5c --- /dev/null +++ b/solenv/gbuild/DotnetTest.mk @@ -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 + \ + \ + \ + +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 >$$@,) + $$(file >>$$@,) + $$(file >>$$@,$$(DOTNET_PROPERTY_ELEMENTS)) + $$(file >>$$@,) + $$(file >>$$@,) + $$(file >>$$@,$$(DOTNET_ITEM_ELEMENTS)) + $$(file >>$$@,) + $$(file >>$$@,) + +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 := net8.0 +$$(gb_DotnetTest_$(1)_project) : DOTNET_PROPERTY_ELEMENTS += false +$$(gb_DotnetTest_$(1)_project) : DOTNET_PROPERTY_ELEMENTS += true +$$(gb_DotnetTest_$(1)_project) : DOTNET_PROPERTY_ELEMENTS += $(1) +$$(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 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 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),) + +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),) + +endef + +# vim: set noet sw=4 ts=4: diff --git a/solenv/gbuild/TargetLocations.mk b/solenv/gbuild/TargetLocations.mk index edfd2459cd62..9b950eb3f94e 100644 --- a/solenv/gbuild/TargetLocations.mk +++ b/solenv/gbuild/TargetLocations.mk @@ -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 \ diff --git a/solenv/gbuild/gbuild.help.txt b/solenv/gbuild/gbuild.help.txt index 7b66d154b73a..640abe863fb3 100644 --- a/solenv/gbuild/gbuild.help.txt +++ b/solenv/gbuild/gbuild.help.txt @@ -83,6 +83,7 @@ AVAILABLE TARGETS o CustomTarget o Dictionary o DotnetLibrary + o DotnetTest o Executable o Extension o ExternalPackage diff --git a/solenv/gbuild/gbuild.mk b/solenv/gbuild/gbuild.mk index 2a2f89cf8f45..b3ae841c1c15 100644 --- a/solenv/gbuild/gbuild.mk +++ b/solenv/gbuild/gbuild.mk @@ -331,6 +331,7 @@ include $(foreach class, \ CliNativeLibrary \ CliUnoApi \ DotnetLibrary \ + DotnetTest \ Zip \ AllLangPackage \ Configuration \