Skip to content

Commit 68ee3e2

Browse files
committed
math_opt fixup
1 parent a814dc1 commit 68ee3e2

4 files changed

Lines changed: 176 additions & 2 deletions

File tree

ortools/math_opt/elemental/python/BUILD.bazel

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
load("@pip_deps//:requirements.bzl", "requirement")
1515
load("@pybind11_bazel//:build_defs.bzl", "pybind_extension")
16-
load("@rules_python//python:defs.bzl", "py_library")
16+
load("@rules_python//python:defs.bzl", "py_library", "py_test")
1717

1818
genrule(
1919
name = "generated_enums",
@@ -59,3 +59,26 @@ pybind_extension(
5959
"@pybind11_protobuf//pybind11_protobuf:native_proto_caster",
6060
],
6161
)
62+
63+
py_test(
64+
name = "enums_test",
65+
srcs = ["enums_test.py"],
66+
deps = [
67+
":enums",
68+
requirement("absl-py"),
69+
],
70+
)
71+
72+
py_test(
73+
name = "elemental_test",
74+
srcs = ["elemental_test.py"],
75+
deps = [
76+
":cpp_elemental",
77+
":enums",
78+
requirement("absl-py"),
79+
requirement("numpy"),
80+
"//ortools/math_opt:model_py_pb2",
81+
"//ortools/math_opt:model_update_py_pb2",
82+
"//ortools/math_opt/python/testing:compare_proto",
83+
],
84+
)

ortools/math_opt/python/testing/BUILD.bazel

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
# See the License for the specific language governing permissions and
1212
# limitations under the License.
1313

14-
load("@rules_python//python:defs.bzl", "py_library")
14+
load("@pip_deps//:requirements.bzl", "requirement")
15+
load("@rules_python//python:defs.bzl", "py_library", "py_test")
1516

1617
package(default_visibility = ["//ortools/math_opt:__subpackages__"])
1718

@@ -20,11 +21,23 @@ py_library(
2021
testonly = 1,
2122
srcs = ["compare_proto.py"],
2223
deps = [
24+
requirement("absl-py"),
2325
"//ortools/math_opt/python:normalize",
2426
"@com_google_protobuf//:protobuf_python",
2527
],
2628
)
2729

30+
py_test(
31+
name = "compare_proto_test",
32+
srcs = ["compare_proto_test.py"],
33+
deps = [
34+
":compare_proto",
35+
requirement("absl-py"),
36+
"//ortools/math_opt:model_py_pb2",
37+
"//ortools/math_opt/python:normalize",
38+
],
39+
)
40+
2841
py_library(
2942
name = "proto_matcher",
3043
testonly = 1,
@@ -34,3 +47,14 @@ py_library(
3447
"@com_google_protobuf//:protobuf_python",
3548
],
3649
)
50+
51+
py_test(
52+
name = "proto_matcher_test",
53+
srcs = ["proto_matcher_test.py"],
54+
deps = [
55+
":proto_matcher",
56+
requirement("absl-py"),
57+
"//ortools/math_opt:model_update_py_pb2",
58+
"//ortools/math_opt:sparse_containers_py_pb2",
59+
],
60+
)
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Copyright 2010-2025 Google LLC
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
"""Test MathOpt's custom proto test assertions."""
15+
16+
from absl.testing import absltest
17+
from ortools.math_opt import model_pb2
18+
from ortools.math_opt.python import normalize
19+
from ortools.math_opt.python.testing import compare_proto
20+
21+
22+
class MathOptProtoAssertionsTest(
23+
absltest.TestCase, compare_proto.MathOptProtoAssertions
24+
):
25+
26+
def test_assertions_match_but_not_equal(self) -> None:
27+
model_with_empty_vars = model_pb2.ModelProto()
28+
model_with_empty_vars.variables.SetInParent()
29+
empty = model_pb2.ModelProto()
30+
with self.assertRaisesRegex(AssertionError, ".*variables.*"):
31+
self.assert_protos_equal(model_with_empty_vars, empty)
32+
with self.assertRaisesRegex(AssertionError, ".*variables.*"):
33+
self.assert_protos_equal(empty, model_with_empty_vars)
34+
35+
self.assert_protos_equiv(model_with_empty_vars, empty)
36+
self.assert_protos_equiv(empty, model_with_empty_vars)
37+
38+
normalize.math_opt_normalize_proto(model_with_empty_vars)
39+
self.assert_protos_equal(model_with_empty_vars, empty)
40+
self.assert_protos_equal(empty, model_with_empty_vars)
41+
self.assert_protos_equiv(model_with_empty_vars, empty)
42+
self.assert_protos_equiv(empty, model_with_empty_vars)
43+
44+
def test_do_not_match(self) -> None:
45+
with_maximize = model_pb2.ModelProto()
46+
with_maximize.objective.maximize = True
47+
empty = model_pb2.ModelProto()
48+
49+
with self.assertRaisesRegex(AssertionError, ".*maximize.*"):
50+
self.assert_protos_equal(with_maximize, empty)
51+
with self.assertRaisesRegex(AssertionError, ".*maximize.*"):
52+
self.assert_protos_equal(empty, with_maximize)
53+
54+
with self.assertRaisesRegex(AssertionError, ".*maximize.*"):
55+
self.assert_protos_equiv(with_maximize, empty)
56+
with self.assertRaisesRegex(AssertionError, ".*maximize.*"):
57+
self.assert_protos_equiv(empty, with_maximize)
58+
59+
60+
if __name__ == "__main__":
61+
absltest.main()
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Copyright 2010-2025 Google LLC
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
from unittest import mock
15+
16+
from absl.testing import absltest
17+
from ortools.math_opt import model_update_pb2
18+
from ortools.math_opt import sparse_containers_pb2
19+
from ortools.math_opt.python.testing import proto_matcher
20+
21+
22+
class _ConsumesUpdate:
23+
24+
def __init__(self):
25+
pass
26+
27+
def on_update(self, update: model_update_pb2.ModelUpdateProto):
28+
pass
29+
30+
31+
class MathOptProtoAssertionsTest(absltest.TestCase):
32+
33+
def test_mock_eq(self):
34+
update1 = model_update_pb2.ObjectiveUpdatesProto(
35+
direction_update=True, offset_update=0.0
36+
)
37+
update2 = model_update_pb2.ObjectiveUpdatesProto(direction_update=True)
38+
update3 = model_update_pb2.ObjectiveUpdatesProto(
39+
direction_update=True,
40+
linear_coefficients=sparse_containers_pb2.SparseDoubleVectorProto(),
41+
)
42+
self.assertFalse(
43+
proto_matcher.MathOptProtoEquivMatcher(update1).__eq__(update2)
44+
)
45+
self.assertTrue(proto_matcher.MathOptProtoEquivMatcher(update1).__ne__(update2))
46+
self.assertTrue(proto_matcher.MathOptProtoEquivMatcher(update2).__eq__(update3))
47+
self.assertFalse(
48+
proto_matcher.MathOptProtoEquivMatcher(update2).__ne__(update3)
49+
)
50+
51+
def test_mock_function_when_equal(self):
52+
consumer = _ConsumesUpdate()
53+
consumer.on_update = mock.MagicMock()
54+
55+
update = model_update_pb2.ModelUpdateProto(deleted_variable_ids=[0, 4, 5])
56+
57+
consumer.on_update(update)
58+
59+
expected = model_update_pb2.ModelUpdateProto(deleted_variable_ids=[0, 4, 5])
60+
consumer.on_update.assert_called_with(
61+
proto_matcher.MathOptProtoEquivMatcher(expected)
62+
)
63+
64+
65+
if __name__ == "__main__":
66+
absltest.main()

0 commit comments

Comments
 (0)