From 1a8b1ee55abf7bba1bbd1894c9481aba6bb5f1b7 Mon Sep 17 00:00:00 2001 From: Talhax55z Date: Tue, 22 Sep 2026 21:06:07 +0500 Subject: [PATCH 1/5] Add anisotropic edge-case tests for SegResNetDS shape validation Signed-off-by: Talhax55z --- tests/test_segresnet_ds.py | 98 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 tests/test_segresnet_ds.py diff --git a/tests/test_segresnet_ds.py b/tests/test_segresnet_ds.py new file mode 100644 index 00000000000..bcc9f547d59 --- /dev/null +++ b/tests/test_segresnet_ds.py @@ -0,0 +1,98 @@ +import unittest +import torch +from parameterized import parameterized + +from monai.networks.nets import SegResNetDS + + +class TestSegResNetDSShapeLogic(unittest.TestCase): + """Tests for shape_factor() and is_valid_shape() in SegResNetDS.""" + + # ---- shape_factor, isotropic (resolution=None) ---- + @parameterized.expand([ + # (spatial_dims, blocks_down, expected_factor) + (2, [1, 2, 2, 4], [8, 8]), + (3, [1, 2, 2, 4], [8, 8, 8]), + (3, [1, 2, 4], [4, 4, 4]), + ]) + def test_shape_factor_isotropic(self, spatial_dims, blocks_down, expected): + model = SegResNetDS( + spatial_dims=spatial_dims, + in_channels=1, + out_channels=1, + blocks_down=blocks_down, + resolution=None, + ) + actual = [int(x) for x in model.shape_factor()] + self.assertEqual(actual, expected) + + # ---- shape_factor, anisotropic (resolution set) ---- + @parameterized.expand([ + # (spatial_dims, blocks_down, resolution, expected_factor) + (3, [1, 2, 2, 4], [1, 1, 5], [8, 8, 2]), + (3, [1, 2, 2, 4], [1, 2, 3], [8, 4, 4]), + ]) + def test_shape_factor_anisotropic(self, spatial_dims, blocks_down, resolution, expected): + model = SegResNetDS( + spatial_dims=spatial_dims, + in_channels=1, + out_channels=1, + blocks_down=blocks_down, + resolution=resolution, + ) + actual = [int(x) for x in model.shape_factor()] + self.assertEqual(actual, expected) + + # ---- is_valid_shape, valid inputs ---- + @parameterized.expand([ + # (spatial_dims, blocks_down, resolution, input_shape) + (2, [1, 2, 2, 4], None, (1, 1, 16, 16)), + (3, [1, 2, 2, 4], None, (1, 1, 16, 16, 16)), + (3, [1, 2, 2, 4], [1, 1, 5], (1, 1, 16, 16, 16)), + (3, [1, 2, 2, 4], [1, 2, 3], (1, 1, 16, 16, 16)), + ]) + def test_is_valid_shape_true(self, spatial_dims, blocks_down, resolution, shape): + model = SegResNetDS( + spatial_dims=spatial_dims, + in_channels=1, + out_channels=1, + blocks_down=blocks_down, + resolution=resolution, + ) + x = torch.zeros(shape) + self.assertTrue(model.is_valid_shape(x)) + + # ---- is_valid_shape, invalid inputs ---- + @parameterized.expand([ + (3, [1, 2, 2, 4], None, (1, 1, 15, 16, 16)), # 15 not divisible by 8 + (3, [1, 2, 2, 4], None, (1, 1, 7, 7, 7)), # 7 not divisible by 8 + (3, [1, 2, 2, 4], [1, 1, 5], (1, 1, 16, 15, 16)), # 15 not divisible by 8 + (3, [1, 2, 2, 4], [1, 2, 3], (1, 1, 16, 16, 15)), # 15 not divisible by 4 + ]) + def test_is_valid_shape_false(self, spatial_dims, blocks_down, resolution, shape): + model = SegResNetDS( + spatial_dims=spatial_dims, + in_channels=1, + out_channels=1, + blocks_down=blocks_down, + resolution=resolution, + ) + x = torch.zeros(shape) + self.assertFalse(model.is_valid_shape(x)) + + # ---- integration: forward pass raises on invalid shape ---- + def test_forward_raises_on_invalid_shape(self): + model = SegResNetDS( + spatial_dims=3, + in_channels=1, + out_channels=1, + blocks_down=[1, 2, 2, 4], + resolution=None, + ) + x = torch.zeros(1, 1, 15, 16, 16) # 15 not divisible by 8 + with self.assertRaises(ValueError): + model(x) + + +if __name__ == "__main__": + unittest.main() From 71f03b7cf3d05c7141e92351ba2692b029e057c0 Mon Sep 17 00:00:00 2001 From: Talhax55z Date: Tue, 22 Sep 2026 21:43:07 +0500 Subject: [PATCH 2/5] Add Google-style docstrings to SegResNetDS test methods Signed-off-by: Talhax55z --- tests/test_segresnet_ds.py | 40 +++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/tests/test_segresnet_ds.py b/tests/test_segresnet_ds.py index bcc9f547d59..d53ec0de89a 100644 --- a/tests/test_segresnet_ds.py +++ b/tests/test_segresnet_ds.py @@ -16,6 +16,14 @@ class TestSegResNetDSShapeLogic(unittest.TestCase): (3, [1, 2, 4], [4, 4, 4]), ]) def test_shape_factor_isotropic(self, spatial_dims, blocks_down, expected): + """ + Test shape_factor() calculation for isotropic (resolution=None) configurations. + + Args: + spatial_dims: Number of spatial dimensions (2 or 3). + blocks_down: List of integers defining the downsampling blocks. + expected: Expected divisor factors per spatial dimension. + """ model = SegResNetDS( spatial_dims=spatial_dims, in_channels=1, @@ -33,6 +41,15 @@ def test_shape_factor_isotropic(self, spatial_dims, blocks_down, expected): (3, [1, 2, 2, 4], [1, 2, 3], [8, 4, 4]), ]) def test_shape_factor_anisotropic(self, spatial_dims, blocks_down, resolution, expected): + """ + Test shape_factor() calculation for anisotropic (resolution set) configurations. + + Args: + spatial_dims: Number of spatial dimensions. + blocks_down: List of integers defining the downsampling blocks. + resolution: List of resolutions for anisotropic scaling. + expected: Expected divisor factors per spatial dimension. + """ model = SegResNetDS( spatial_dims=spatial_dims, in_channels=1, @@ -52,6 +69,15 @@ def test_shape_factor_anisotropic(self, spatial_dims, blocks_down, resolution, e (3, [1, 2, 2, 4], [1, 2, 3], (1, 1, 16, 16, 16)), ]) def test_is_valid_shape_true(self, spatial_dims, blocks_down, resolution, shape): + """ + Test is_valid_shape() returns True for inputs with valid shapes. + + Args: + spatial_dims: Number of spatial dimensions. + blocks_down: List of integers defining the downsampling blocks. + resolution: List of resolutions for anisotropic scaling. + shape: Input tensor shape to validate. + """ model = SegResNetDS( spatial_dims=spatial_dims, in_channels=1, @@ -70,6 +96,15 @@ def test_is_valid_shape_true(self, spatial_dims, blocks_down, resolution, shape) (3, [1, 2, 2, 4], [1, 2, 3], (1, 1, 16, 16, 15)), # 15 not divisible by 4 ]) def test_is_valid_shape_false(self, spatial_dims, blocks_down, resolution, shape): + """ + Test is_valid_shape() returns False for inputs with invalid shapes. + + Args: + spatial_dims: Number of spatial dimensions. + blocks_down: List of integers defining the downsampling blocks. + resolution: List of resolutions for anisotropic scaling. + shape: Input tensor shape to validate. + """ model = SegResNetDS( spatial_dims=spatial_dims, in_channels=1, @@ -82,6 +117,9 @@ def test_is_valid_shape_false(self, spatial_dims, blocks_down, resolution, shape # ---- integration: forward pass raises on invalid shape ---- def test_forward_raises_on_invalid_shape(self): + """ + Test that the forward pass raises ValueError when the input shape is invalid. + """ model = SegResNetDS( spatial_dims=3, in_channels=1, @@ -95,4 +133,4 @@ def test_forward_raises_on_invalid_shape(self): if __name__ == "__main__": - unittest.main() + unittest.main() \ No newline at end of file From 5649db8f7d682c1d0dd336d005692dde30b7bbb4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 22 Sep 2026 16:09:24 +0000 Subject: [PATCH 3/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Signed-off-by: Talhax55z # Conflicts: # tests/test_segresnet_ds.py --- tests/test_segresnet_ds.py | 93 +++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 52 deletions(-) diff --git a/tests/test_segresnet_ds.py b/tests/test_segresnet_ds.py index d53ec0de89a..6c7de768f27 100644 --- a/tests/test_segresnet_ds.py +++ b/tests/test_segresnet_ds.py @@ -1,4 +1,7 @@ +from __future__ import annotations + import unittest + import torch from parameterized import parameterized @@ -9,12 +12,14 @@ class TestSegResNetDSShapeLogic(unittest.TestCase): """Tests for shape_factor() and is_valid_shape() in SegResNetDS.""" # ---- shape_factor, isotropic (resolution=None) ---- - @parameterized.expand([ - # (spatial_dims, blocks_down, expected_factor) - (2, [1, 2, 2, 4], [8, 8]), - (3, [1, 2, 2, 4], [8, 8, 8]), - (3, [1, 2, 4], [4, 4, 4]), - ]) + @parameterized.expand( + [ + # (spatial_dims, blocks_down, expected_factor) + (2, [1, 2, 2, 4], [8, 8]), + (3, [1, 2, 2, 4], [8, 8, 8]), + (3, [1, 2, 4], [4, 4, 4]), + ] + ) def test_shape_factor_isotropic(self, spatial_dims, blocks_down, expected): """ Test shape_factor() calculation for isotropic (resolution=None) configurations. @@ -25,21 +30,19 @@ def test_shape_factor_isotropic(self, spatial_dims, blocks_down, expected): expected: Expected divisor factors per spatial dimension. """ model = SegResNetDS( - spatial_dims=spatial_dims, - in_channels=1, - out_channels=1, - blocks_down=blocks_down, - resolution=None, + spatial_dims=spatial_dims, in_channels=1, out_channels=1, blocks_down=blocks_down, resolution=None ) actual = [int(x) for x in model.shape_factor()] self.assertEqual(actual, expected) # ---- shape_factor, anisotropic (resolution set) ---- - @parameterized.expand([ - # (spatial_dims, blocks_down, resolution, expected_factor) - (3, [1, 2, 2, 4], [1, 1, 5], [8, 8, 2]), - (3, [1, 2, 2, 4], [1, 2, 3], [8, 4, 4]), - ]) + @parameterized.expand( + [ + # (spatial_dims, blocks_down, resolution, expected_factor) + (3, [1, 2, 2, 4], [1, 1, 5], [8, 8, 2]), + (3, [1, 2, 2, 4], [1, 2, 3], [8, 4, 4]), + ] + ) def test_shape_factor_anisotropic(self, spatial_dims, blocks_down, resolution, expected): """ Test shape_factor() calculation for anisotropic (resolution set) configurations. @@ -51,23 +54,21 @@ def test_shape_factor_anisotropic(self, spatial_dims, blocks_down, resolution, e expected: Expected divisor factors per spatial dimension. """ model = SegResNetDS( - spatial_dims=spatial_dims, - in_channels=1, - out_channels=1, - blocks_down=blocks_down, - resolution=resolution, + spatial_dims=spatial_dims, in_channels=1, out_channels=1, blocks_down=blocks_down, resolution=resolution ) actual = [int(x) for x in model.shape_factor()] self.assertEqual(actual, expected) # ---- is_valid_shape, valid inputs ---- - @parameterized.expand([ - # (spatial_dims, blocks_down, resolution, input_shape) - (2, [1, 2, 2, 4], None, (1, 1, 16, 16)), - (3, [1, 2, 2, 4], None, (1, 1, 16, 16, 16)), - (3, [1, 2, 2, 4], [1, 1, 5], (1, 1, 16, 16, 16)), - (3, [1, 2, 2, 4], [1, 2, 3], (1, 1, 16, 16, 16)), - ]) + @parameterized.expand( + [ + # (spatial_dims, blocks_down, resolution, input_shape) + (2, [1, 2, 2, 4], None, (1, 1, 16, 16)), + (3, [1, 2, 2, 4], None, (1, 1, 16, 16, 16)), + (3, [1, 2, 2, 4], [1, 1, 5], (1, 1, 16, 16, 16)), + (3, [1, 2, 2, 4], [1, 2, 3], (1, 1, 16, 16, 16)), + ] + ) def test_is_valid_shape_true(self, spatial_dims, blocks_down, resolution, shape): """ Test is_valid_shape() returns True for inputs with valid shapes. @@ -79,22 +80,20 @@ def test_is_valid_shape_true(self, spatial_dims, blocks_down, resolution, shape) shape: Input tensor shape to validate. """ model = SegResNetDS( - spatial_dims=spatial_dims, - in_channels=1, - out_channels=1, - blocks_down=blocks_down, - resolution=resolution, + spatial_dims=spatial_dims, in_channels=1, out_channels=1, blocks_down=blocks_down, resolution=resolution ) x = torch.zeros(shape) self.assertTrue(model.is_valid_shape(x)) # ---- is_valid_shape, invalid inputs ---- - @parameterized.expand([ - (3, [1, 2, 2, 4], None, (1, 1, 15, 16, 16)), # 15 not divisible by 8 - (3, [1, 2, 2, 4], None, (1, 1, 7, 7, 7)), # 7 not divisible by 8 - (3, [1, 2, 2, 4], [1, 1, 5], (1, 1, 16, 15, 16)), # 15 not divisible by 8 - (3, [1, 2, 2, 4], [1, 2, 3], (1, 1, 16, 16, 15)), # 15 not divisible by 4 - ]) + @parameterized.expand( + [ + (3, [1, 2, 2, 4], None, (1, 1, 15, 16, 16)), # 15 not divisible by 8 + (3, [1, 2, 2, 4], None, (1, 1, 7, 7, 7)), # 7 not divisible by 8 + (3, [1, 2, 2, 4], [1, 1, 5], (1, 1, 16, 15, 16)), # 15 not divisible by 8 + (3, [1, 2, 2, 4], [1, 2, 3], (1, 1, 16, 16, 15)), # 15 not divisible by 4 + ] + ) def test_is_valid_shape_false(self, spatial_dims, blocks_down, resolution, shape): """ Test is_valid_shape() returns False for inputs with invalid shapes. @@ -106,11 +105,7 @@ def test_is_valid_shape_false(self, spatial_dims, blocks_down, resolution, shape shape: Input tensor shape to validate. """ model = SegResNetDS( - spatial_dims=spatial_dims, - in_channels=1, - out_channels=1, - blocks_down=blocks_down, - resolution=resolution, + spatial_dims=spatial_dims, in_channels=1, out_channels=1, blocks_down=blocks_down, resolution=resolution ) x = torch.zeros(shape) self.assertFalse(model.is_valid_shape(x)) @@ -120,17 +115,11 @@ def test_forward_raises_on_invalid_shape(self): """ Test that the forward pass raises ValueError when the input shape is invalid. """ - model = SegResNetDS( - spatial_dims=3, - in_channels=1, - out_channels=1, - blocks_down=[1, 2, 2, 4], - resolution=None, - ) + model = SegResNetDS(spatial_dims=3, in_channels=1, out_channels=1, blocks_down=[1, 2, 2, 4], resolution=None) x = torch.zeros(1, 1, 15, 16, 16) # 15 not divisible by 8 with self.assertRaises(ValueError): model(x) if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() From 94aefc095c02fa56f4b4fea3689c68e2c78e0dfe Mon Sep 17 00:00:00 2001 From: Talhax55z Date: Thu, 1 Oct 2026 23:06:50 +0500 Subject: [PATCH 4/5] Add license header to SegResNetDS tests Signed-off-by: Talhax55z --- tests/test_segresnet_ds.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_segresnet_ds.py b/tests/test_segresnet_ds.py index 6c7de768f27..e21ed302692 100644 --- a/tests/test_segresnet_ds.py +++ b/tests/test_segresnet_ds.py @@ -1,3 +1,14 @@ +# Copyright (c) MONAI Consortium +# 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 __future__ import annotations import unittest From 0babbee675aeed02a38f854d66f5a5fae75e586d Mon Sep 17 00:00:00 2001 From: Muhammad Talha Date: Tue, 6 Oct 2026 13:24:49 +0500 Subject: [PATCH 5/5] Retrigger CI Signed-off-by: Muhammad Talha