diff --git a/dimos/core/test_lcmmsg_gen.py b/dimos/core/test_lcmmsg_gen.py new file mode 100644 index 0000000000..231a3ce9ad --- /dev/null +++ b/dimos/core/test_lcmmsg_gen.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 + +# Copyright 2025 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from lcm_msgs.geometry_msgs import Orientation, Pose, PoseStamped, Vector3 +from lcm_msgs.std_msgs import Header + + +# None of the tests actually pass apart from the first two. +# The rest of the tests are a proposal for functionality to be added. +# +# Below mutable init is how current lcmgen can only be used, +# This is not very ergonomical, and these are the most common objects we use, +# so we need a way to both have a better init for them by default, coming +# out of lcmgen, +# as well as to have a better way to modify individual types by hand for +# type specific convinience methods. +# +# Some examples: +# header taking datetime or float, instead of a weird ros timestamp dictionary format, +# Quaternion having .yaw() pitch() or to_euler() -> Vector3 methods,etc +# Vector taking a list or tuple as init, not just kwargs +# +def test_vector_current_init(): + vector = Vector3() + vector.x = 1.0 + vector.y = 2.0 + vector.z = 3.0 + + +def test_vector_defaults(): + vector = Vector3() + assert vector.x == 0.0 + assert vector.y == 0.0 + assert vector.z == 0.0 + + +def test_vector_init(): + vector = Vector3(x=1.0, y=2.0, z=3.0) + assert vector.x == 1.0 + assert vector.y == 2.0 + assert vector.z == 3.0 + + +# I'm not sure if easily achievable, +# but this is a much better interface +def test_vector_args_init(): + vector = Vector3(1.0, 2.0, 3.0) + assert vector.x == 1.0 + assert vector.y == 2.0 + assert vector.z == 3.0 + + +# if we are using these types across the platform, they are the most common +# objects used, we have to be able to subclass and implement convinience +# methods (like above positional arg init) +# +# how can we hand- add to a specific autogenerated lcm_msg type? +# while also keeping the new class within the original dep structure +# (so Pose would refer to the new convinient Vector3 subclass, +# without recoding the Pose itself?) + + +def test_vector_partial_defaults(): + vector = Vector3(x=1.0) + assert vector.x == 1.0 + assert vector.y == 0.0 + assert vector.z == 0.0 + + +def test_vector_encode_decode(): + msg = Vector3(x=1.0, y=2.0, z=3.0).encode() + assert isinstance(msg, bytes) + vector = Vector3.decode(msg) + assert vector.x == 1.0 + assert vector.y == 2.0 + assert vector.z == 3.0 + + +def test_pose_stamped_init(): + pose = PoseStamped( + pose=Pose( + position=Vector3(1.0, 2.0, 3.0), + orientation=Orientation(1.0, 2.0, 3.0, 4.0), + ), + header=Header(stamp=1234567890, frame_id="test_frame"), + ) + + +# not sure if we can achieve this automatically easily, but this is +# a much better interface +def test_pose_fancy_init(): + pose = PoseStamped( + # depeer init implicit + position=Vector3(1.0, 2.0, 3.0), + orientation=Orientation(1.0, 2.0, 3.0, 4.0), + stamp=1234567890, + frame_id="test_frame", + ) + + assert pose.pose.position.x == 1.0 + + +def test_pose_partial_fancy_init(): + # partially implicit init + pose = PoseStamped( + # pose explicit + pose=Pose( + # I'm hoping for positional argument support here + position=Vector3(1.0, 2.0, 3.0), + orientation=Orientation(1.0, 2.0, 3.0, 4.0), + ), + # header implicit + stamp=1234567890, + frame_id="test_frame", + ) + + assert pose.pose.position.x == 1.0 + + # can Stamped modules provide access to the underlying data + # directly? Maybe manual Stamped subclass? + assert pose.position.y == 2.0