diff --git a/lib/GPH/PHPMD.pm b/lib/GPH/PHPMD.pm index 33fd174..0f13b28 100644 --- a/lib/GPH/PHPMD.pm +++ b/lib/GPH/PHPMD.pm @@ -45,33 +45,33 @@ sub new { # # Returns: ruleset.xml config file string sub getConfig { - my $self = shift; + my $self = shift; - my $ruleset = $self->{generator}->buildElement('ruleset', undef, undef, ( - 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation' => 'http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd', - 'xsi:noNamespaceSchemaLocation' => 'http://pmd.sf.net/ruleset_xml_schema.xsd', - 'name' => "$self->{owner} PHPMD rule set", - )); + my $ruleset = $self->{generator}->buildElement((name => 'ruleset', attributes => { + 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:schemaLocation' => 'http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd', + 'xsi:noNamespaceSchemaLocation' => 'http://pmd.sf.net/ruleset_xml_schema.xsd', + 'name' => "$self->{owner} PHPMD rule set", + })); - $ruleset->setNamespace('http://pmd.sf.net/ruleset/1.0.0'); + $ruleset->setNamespace('http://pmd.sf.net/ruleset/1.0.0'); - my $rule = $self->{generator}->buildElement('rule', undef, $ruleset, ( - 'ref' => 'rulesets/codesize.xml/CyclomaticComplexity' - )); + my $rule = $self->{generator}->buildElement((name => 'rule', parent => $ruleset, attributes => { + 'ref' => 'rulesets/codesize.xml/CyclomaticComplexity' + })); - my $properties = $self->{generator}->buildElement('properties', undef, $rule); + my $properties = $self->{generator}->buildElement((name => 'properties', parent => $rule)); - $self->{generator}->buildElement('property', undef, $properties, ( - 'name' => 'reportLevel', - 'value' => $self->{cycloLevel} - )); + $self->{generator}->buildElement((name => 'property', parent => $properties, attributes => { + 'name' => 'reportLevel', + 'value' => $self->{cycloLevel} + })); - my $dom = $self->{generator}->getDom(); + my $dom = $self->{generator}->getDom(); - $dom->setDocumentElement($ruleset); + $dom->setDocumentElement($ruleset); - return ($dom->toString(1)); + return ($dom->toString(1)); } 1; \ No newline at end of file diff --git a/lib/GPH/Psalm.pm b/lib/GPH/Psalm.pm index c3439c7..14ccbf6 100644 --- a/lib/GPH/Psalm.pm +++ b/lib/GPH/Psalm.pm @@ -61,7 +61,7 @@ sub new { sub getConfig { my $self = shift; - my $psalm = $self->{generator}->buildElement('psalm', undef, undef, ( + my $psalm = $self->{generator}->buildElement((name => 'psalm', attributes => { 'resolveFromConfigFile' => 'true', 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation' => 'https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd', @@ -69,35 +69,35 @@ sub getConfig { 'cacheDirectory' => $self->{cacheDir}, 'errorBaseline' => $self->{baseline}, 'findUnusedBaselineEntry' => $self->{baselineCheck}, - )); + })); $psalm->setNamespace('https://getpsalm.org/schema/config'); - my $projectFiles = $self->{generator}->buildElement('projectFiles', undef, $psalm); + my $projectFiles = $self->{generator}->buildElement((name => 'projectFiles', parent => $psalm)); foreach my $path (@{$self->{paths}}) { - $self->{generator}->buildElement('directory', undef, $projectFiles, ( + $self->{generator}->buildElement((name => 'directory', parent => $projectFiles, attributes => { 'name' => $path, - )); + })); } if (defined $self->{ignoredDirectories}) { - my $ignoreFiles = $self->{generator}->buildElement('ignoreFiles', undef, $projectFiles); + my $ignoreFiles = $self->{generator}->buildElement((name => 'ignoreFiles', parent => $projectFiles)); foreach my $path (@{$self->{ignoredDirectories}}) { - $self->{generator}->buildElement('directory', undef, $ignoreFiles, ( + $self->{generator}->buildElement((name => 'directory', parent => $ignoreFiles, attributes => { 'name' => $path, - )); + })); } } if (defined $self->{plugins}) { - my $plugins = $self->{generator}->buildElement('plugins', undef, $psalm); + my $plugins = $self->{generator}->buildElement((name => 'plugins', parent => $psalm)); foreach my $plugin (@{$self->{plugins}}) { - $self->{generator}->buildElement('pluginClass', undef, $plugins, ( + $self->{generator}->buildElement((name => 'pluginClass', parent => $plugins, attributes => { 'class' => $plugin, - )); + })); } } diff --git a/lib/GPH/XMLHelper.pm b/lib/GPH/XMLHelper.pm index 2f2c4d9..49803ba 100644 --- a/lib/GPH/XMLHelper.pm +++ b/lib/GPH/XMLHelper.pm @@ -5,6 +5,7 @@ # # Revisions: 2023-09-03 - created # 2024-02-10 - namespaced module, bugfixes and unit tests +# 2024-02-12 - constructor now requires named arguments #------------------------------------------------------------------------------ package GPH::XMLHelper; @@ -33,32 +34,36 @@ sub new { #------------------------------------------------------------------------------ # Build element # -# Inputs: 0) string: name of the element -# 1) mixed: value of the element -# 2) LibXML::Element object: parent element -# 3) list: element attributes +# Inputs: name => (string) name of the element +# value => (string) value of the element +# parent => (LibXML::Element object) parent element +# attributes => (hash) element attributes # # Returns: LibXML::Element object sub buildElement { - my ($self, $name, $value, $parent, %attributes) = @_; + my ($self, %args) = @_; - my $element = $self->{dom}->createElement($name); + (exists($args{name})) or die "$!"; - foreach my $key (sort keys %attributes) { - if (defined $attributes{$key}) { - $element->{$key} = $attributes{$key}; + my $element = $self->{dom}->createElement($args{name}); + + if (exists($args{attributes})) { + foreach my $key (sort keys %{$args{attributes}}) { + if (defined $args{attributes}{$key}) { + $element->{$key} = $args{attributes}{$key}; + } + } } - } - if (defined $value) { - $element->appendText($value); - } + if (defined $args{value}) { + $element->appendText($args{value}); + } - if (defined $parent) { - $parent->appendChild($element); - } + if (defined $args{parent}) { + $args{parent}->appendChild($element); + } - return $element; + return $element; } #------------------------------------------------------------------------------ diff --git a/t/unit/GPH/XMLHelper.t b/t/unit/GPH/XMLHelper.t new file mode 100644 index 0000000..ac8a819 --- /dev/null +++ b/t/unit/GPH/XMLHelper.t @@ -0,0 +1,137 @@ +#!/usr/bin/perl +package t::unit::GPH::XMLHelper; + +use strict; +use warnings; + +use Test2::V0 -target => 'GPH::XMLHelper'; +use Test2::Tools::Spec; +use Data::Dumper; + +local $SIG{__WARN__} = sub {}; + +describe "class `$CLASS`" => sub { + tests 'it can be instantiated' => sub { + can_ok($CLASS, 'new'); + }; + + tests "mandatory element options" => sub { + my $object = $CLASS->new(); + + ok(dies {$object->buildElement((attributes => {}))}, 'died with missing name') or note($@); + ok(lives {$object->buildElement((name => 'foo'))}, 'lives with mandatory options') or note($@); + }; + + tests 'object validation' => sub { + my ($object, $exception, $warnings); + $exception = dies { + $warnings = warns { + $object = $CLASS->new(); + }; + }; + + is($exception, undef, 'no exception thrown'); + is($warnings, 0, 'no warnings generated'); + is( + $object, + object { + field dom => object { + prop blessed => 'XML::LibXML::Document'; + }; + }, + 'object as expected', + Dumper($object) + ); + + }; +}; + +describe 'test element' => sub { + my (%args, $element, $expected_xml); + + case 'name value attributes' => sub { + %args = ( + name => 'foo', + value => 'bar', + attributes => { + 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance' + } + ); + $expected_xml = 'bar'; + }; + + case 'name' => sub { + %args = ( + name => 'foo', + ); + $expected_xml = ''; + }; + + case 'name value' => sub { + %args = ( + name => 'foo', + value => 'bar', + ); + $expected_xml = 'bar'; + }; + + tests 'element generation' => sub { + my ($object, $exception, $warnings); + $exception = dies { + $warnings = warns { + $object = $CLASS->new(); + $element = $object->buildElement(%args); + }; + }; + + is($exception, undef, 'no exception thrown'); + is($warnings, 0, 'no warnings generated'); + + is( + $element->toString(), + $expected_xml, + 'element as expected', + Dumper($element) + ); + }; +}; + +describe 'test paren element' => sub { + my ($object, $dom, $element, $exception, $warnings); + + $exception = dies { + $warnings = warns { + $object = $CLASS->new(); + $element = $object->buildElement(( + name => 'foo', + attributes => { + 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance' + } + )); + + $object->buildElement(( + name => 'bar', + parent => $element, + value => 'baz', + )); + + $dom = $object->getDom(); + $dom->setDocumentElement($element); + }; + }; + + is($exception, undef, 'no exception thrown'); + is($warnings, 0, 'no warnings generated'); + + is( + $dom->toString(), + ' +baz +', + 'parent child element as expected', + Dumper($dom->toString()) + ) +}; + +done_testing(); +