NAME

Test::Neo4j::Types - Tools for testing Neo4j type modules

VERSION

version 0.04

OVERVIEW

This module distribution is experimental. Should the experiment be deemed successful, it will eventually be merged with the existing Neo4j-Types distribution.

You probably shouldn't be using this module at this time, because the requirements it checks for are evolving and might shift under your feet at any moment. For further information, see johannessen/neo4j-types Version 2 (milestone).

SYNOPSIS

# For a node class that happens to have a new()
# constructor with parameters that match the ones
# given here exactly:
neo4j_node_ok 'Local::Node', \&Local::Node::new;

# For a node data structure that happens to match
# the given parameters exactly:
neo4j_node_ok 'Local::Node', sub {
  my ($class, $params) = @_;
  return bless { %$params }, $class;
};

# For a relationship data structure that needs
# adapting from the given parameters:
neo4j_relationship_ok 'Local::Reln', sub {
  my ($class, $params) = @_;
  return bless {
    %$params,
    start => $params->{start_id},
    end   => $params->{end_id},
  }, $class;
};

# For the typical path data structure:
neo4j_path_ok 'Local::Path', sub {
  my ($class, $elements) = @_;
  return bless [ @$elements ], $class;
};

# For spatial / temporal data structures:
neo4j_point_ok 'Local::Point', sub {...};
neo4j_datetime_ok 'Local::Temporal::Instant', sub {...};
neo4j_duration_ok 'Local::Temporal::Duration', sub {...};

DESCRIPTION

Offers a simple way to test your Neo4j::Types implementation for correctness. These test tools not only verify that the required methods are provided, they also try to verify that the methods actually work as expected. While the checks provided by this module certainly don't cover all requirements, they do cover many of them.

It is anticipated that the checks these tools perform will be expanded in future. If this worries you, you should consider only using these tools for author tests. That said, if your code is on CPAN and declares this module as a dependency, the author of this module will take every effort to avoid problems caused by such changes.

FUNCTIONS

Test::Neo4j::Types offers the following functions. All functions are exported by default.

neo4j_datetime_ok

sub datetime_new ($class, $params) {
  return bless { ... }, $class;
}
neo4j_datetime_ok $datetime_class, \&datetime_new;
neo4j_datetime_ok $datetime_class, \&datetime_new, $subtest_name;

Verifies that $datetime_class is a package that implements the interface specified for temporal instants by Neo4j::Types.

\&datetime_new must be a reference to a subroutine that can construct a new temporal instant of the type $datetime_class based on the parameters provided in the hash ref $params. The parameters have names exactly matching the methods in Neo4j::Types::DateTime, but epoch and type are not provided:

$params = {
  days        => 6560,    # 1987-12-18
  nanoseconds => 0,
  seconds     => 72000,   # 20:00 UTC
  tz_name     => 'America/Los_Angeles',
  tz_offset   => -28800,  # UTC-08
};

neo4j_duration_ok

sub duration_new ($class, $params) {
  return bless { ... }, $class;
}
neo4j_duration_ok $duration_class, \&duration_new;
neo4j_duration_ok $duration_class, \&duration_new, $subtest_name;

Verifies that $duration_class is a package that implements the interface specified for temporal durations by Neo4j::Types.

\&duration_new must be a reference to a subroutine that can construct a new temporal instant of the type $duration_class based on the parameters provided in the hash ref $params. The parameters have names exactly matching the methods in Neo4j::Types::Duration:

$params = {
  months      => 18,      # 1.5 years
  days        => 42,      # 12 weeks
  seconds     => 172800,  # 48 hours
  nanoseconds => 0,
};

neo4j_node_ok

sub node_new ($class, $params) {
  return bless { ... }, $class;
}
neo4j_node_ok $node_class, \&node_new;
neo4j_node_ok $node_class, \&node_new, $subtest_name;

Verifies that $node_class is a package that implements the interface specified for nodes by Neo4j::Types.

\&node_new must be a reference to a subroutine that can construct a new node of the type $node_class based on the parameters provided in the hash ref $params. The parameters have names exactly matching the methods in Neo4j::Types::Node:

$params = {
  element_id => '4:a9bd8c39-9afb-4474-9890-c074b2002cf5:47',
  id         => 47,
  labels     => ['Label'],
  properties => { key => 'value' },
};

neo4j_path_ok

sub path_new ($class, $elements) {
  return bless [ @$elements ], $class;
}
neo4j_path_ok $path_class, \&path_new;
neo4j_path_ok $path_class, \&path_new, $subtest_name;

Verifies that $path_class is a package that implements the interface specified for paths by Neo4j::Types.

\&path_new must be a reference to a subroutine that can construct a new path of the type $path_class based on the elements provided in the array ref $elements. The elements are alternating between references that represent nodes and relationships in the exact same order as for "elements" in Neo4j::Types::Path:

$elements = [
  $node_0,
  $relationship_0,
  $node_1,
  $relationship_1,
  $node_2,
];

Inside path_new, these references will purport to perform the Neo4j::Types::Node and Neo4j::Types::Relationship roles, but shall be treated as opaque. Calling any methods other than ->DOES() on these references may fail.

neo4j_point_ok

sub point_new ($class, $params) {
  return bless { ... }, $class;
}
neo4j_point_ok $point_class, \&point_new;
neo4j_point_ok $point_class, \&point_new, $subtest_name;

Verifies that $point_class is a package that implements the interface specified for spatial points by Neo4j::Types.

\&point_new must be a reference to a subroutine that can construct a new node of the type $point_class based on the parameters provided in the hash ref $params. The parameters have names exactly matching the methods in Neo4j::Types::Point:

$params = {
  srid        => 4326,
  coordinates => [ $x, $y, $z ],
};

neo4j_relationship_ok

sub rel_new ($class, $params) {
  return bless { ... }, $class;
}
neo4j_relationship_ok $rel_class, \&rel_new;
neo4j_relationship_ok $rel_class, \&rel_new, $subtest_name;

Verifies that $rel_class is a package that implements the interface specified for relationships by Neo4j::Types.

\&rel_new must be a reference to a subroutine that can construct a new relationship of the type $rel_class based on the parameters provided in the hash ref $params. The parameters have names exactly matching the methods in Neo4j::Types::Relationship:

$params = {
  element_id       => '5:a9bd8c39-9afb-4474-9890-c074b2002cf5:23',
  id               => 23,
  start_element_id => '4:a9bd8c39-9afb-4474-9890-c074b2002cf5:81',
  start_id         => 81,
  end_element_id   => '4:a9bd8c39-9afb-4474-9890-c074b2002cf5:82',
  end_id           => 82,
  properties       => { key => 'value' },
  type             => 'TYPE',
};

BUGS AND LIMITATIONS

The diagnostics are not particularly great. All of these tools are implemented as simple subtests. You can run prove -v and obtain details about any failing checks, but you'll probably have to compare the TAP output with this modules's source code to make sense of them. Unfortunately, the tool source code is more optimised for compactness that for readability, which of course means me asking people to "just read the code" is quite shameless. However, because the number of users this module is anticipated to have is very low (maybe two or so), this limitation is unlikely to be addressed.

The individual test names inside the subtests could be (and probably should be) improved though. Ideally, the names of failed tests would make sense even without reading the source.

As a consequence of the subtests, it appears to be difficult to verify that these tools correctly identify non-conforming implementations, which is of course the primary job of these tools. So the testing of the tools themselves is incomplete.

Optional / "should" requirements may need to be checked, with warnings or at least diag messages issued if not met. These warnings need to be individually selectable. One (naive but perhaps adequate) way to implement this might be a global @Test::Neo4j::Types::no_warnings variable, which users could then localise and configure as required.

If these tools are ever developed further than this, switching to Test2::Manual::Tooling should be considered.

SEE ALSO

Neo4j::Types::ImplementorNotes

AUTHOR

Arne Johannessen <ajnn@cpan.org>

If you contact me by email, please make sure you include the word "Perl" in your subject header to help beat the spam filters.

COPYRIGHT AND LICENSE

This software is Copyright (c) 2023 by Arne Johannessen.

This is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0 or (at your option) the same terms as the Perl 5 programming language system itself.