Skip to content

Commit 088a732

Browse files
authored
[Utilities] improve test coverage (#2669)
1 parent 93694da commit 088a732

File tree

9 files changed

+151
-29
lines changed

9 files changed

+151
-29
lines changed

src/MathOptInterface.jl

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -394,31 +394,25 @@ import PrecompileTools
394394

395395
PrecompileTools.@setup_workload begin
396396
PrecompileTools.@compile_workload begin
397-
let
398-
optimizer =
399-
() -> Utilities.MockOptimizer(
400-
Utilities.UniversalFallback(Utilities.Model{Float64}()),
401-
)
402-
model = Utilities.CachingOptimizer(
403-
Utilities.UniversalFallback(Utilities.Model{Float64}()),
404-
instantiate(optimizer; with_bridge_type = Float64),
405-
)
406-
set(model, Silent(), true)
407-
x = add_variables(model, 3)
408-
add_constraint(model, x[1], ZeroOne())
409-
add_constraint(model, x[2], Integer())
410-
add_constraint(model, x[1], GreaterThan(0.0))
411-
add_constraint(model, x[2], LessThan(0.0))
412-
add_constraint(model, x[3], EqualTo(0.0))
413-
f = 1.0 * x[1] + x[2] + x[3]
414-
add_constraint(model, f, GreaterThan(0.0))
415-
add_constraint(model, f, LessThan(0.0))
416-
add_constraint(model, f, EqualTo(0.0))
417-
y, _ = add_constrained_variables(model, Nonnegatives(2))
418-
set(model, ObjectiveSense(), MAX_SENSE)
419-
set(model, ObjectiveFunction{typeof(f)}(), f)
420-
optimize!(model)
421-
end
397+
model = Utilities.CachingOptimizer(
398+
Utilities.UniversalFallback(Utilities.Model{Float64}()),
399+
instantiate(Utilities.MockOptimizer; with_bridge_type = Float64),
400+
)
401+
set(model, Silent(), true)
402+
x = add_variables(model, 3)
403+
add_constraint(model, x[1], ZeroOne())
404+
add_constraint(model, x[2], Integer())
405+
add_constraint(model, x[1], GreaterThan(0.0))
406+
add_constraint(model, x[2], LessThan(0.0))
407+
add_constraint(model, x[3], EqualTo(0.0))
408+
f = 1.0 * x[1] + x[2] + x[3]
409+
add_constraint(model, f, GreaterThan(0.0))
410+
add_constraint(model, f, LessThan(0.0))
411+
add_constraint(model, f, EqualTo(0.0))
412+
y, _ = add_constrained_variables(model, Nonnegatives(2))
413+
set(model, ObjectiveSense(), MAX_SENSE)
414+
set(model, ObjectiveFunction{typeof(f)}(), f)
415+
optimize!(model)
422416
end
423417
end
424418

src/Test/test_attribute.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ function test_attribute_TimeLimitSec(model::MOI.AbstractOptimizer, ::Config)
172172
try
173173
return MOI.get(model, MOI.TimeLimitSec())
174174
catch err
175-
@assert err isa MOI.GetAttributeNotAllowed(MOI.TimeLimitSec())
175+
@assert err isa MOI.GetAttributeNotAllowed{MOI.TimeLimitSec}
176176
end
177177
return
178178
end

src/Utilities/cachingoptimizer.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,8 @@ function MOI.optimize!(m::CachingOptimizer)
320320
for attr in MOI.get(m, MOI.ListOfModelAttributesSet())
321321
if attr isa MOI.AbstractCallback
322322
attach_optimizer(m)
323-
return MOI.optimize!(m)
323+
MOI.optimize!(m)
324+
return
324325
end
325326
end
326327
indexmap, copied = MOI.optimize!(m.optimizer, m.model_cache)

src/Utilities/mockoptimizer.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ function MockOptimizer(
131131
)
132132
end
133133

134+
function MockOptimizer(::Type{T} = Float64; kwargs...) where {T}
135+
inner = UniversalFallback(Utilities.Model{T}())
136+
return MockOptimizer(inner, T; kwargs...)
137+
end
138+
134139
"""
135140
All user-facing indices are xor'd with this mask to produce unusual indices.
136141
This is good at catching bugs in solvers which assume indices are ordered 1, 2,

src/Utilities/universalfallback.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -783,8 +783,7 @@ function MOI.set(
783783
ci::MOI.ConstraintIndex{F,S},
784784
value,
785785
) where {F,S}
786-
if MOI.supports_constraint(uf.model, F, S) &&
787-
MOI.supports(uf.model, attr, MOI.ConstraintIndex{F,S})
786+
if _model_supports_attribute(uf.model, attr, MOI.ConstraintIndex{F,S})
788787
MOI.set(uf.model, attr, ci, value)
789788
else
790789
_set(uf, attr, ci, value)

test/Test/Test.jl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,31 @@ function test_error_handler()
246246
return
247247
end
248248

249+
"Test a model that errors getting time limit unless it was previously set"
250+
mutable struct ModelTimeLimitSecErrorIfNotSet <: MOI.AbstractOptimizer
251+
time_limit::Union{Missing,Nothing,Float64}
252+
end
253+
254+
MOI.supports(::ModelTimeLimitSecErrorIfNotSet, ::MOI.TimeLimitSec) = true
255+
256+
function MOI.get(model::ModelTimeLimitSecErrorIfNotSet, attr::MOI.TimeLimitSec)
257+
if model.time_limit === missing
258+
throw(MOI.GetAttributeNotAllowed(attr))
259+
end
260+
return model.time_limit::Union{Nothing,Float64}
261+
end
262+
263+
function MOI.set(model::ModelTimeLimitSecErrorIfNotSet, ::MOI.TimeLimitSec, v)
264+
model.time_limit = v
265+
return
266+
end
267+
268+
function test_attribute_TimeLimitSec()
269+
model = ModelTimeLimitSecErrorIfNotSet(missing)
270+
MOI.Test.test_attribute_TimeLimitSec(model, MOI.Test.Config())
271+
return
272+
end
273+
249274
end # module
250275

251276
TestTest.runtests()

test/Utilities/cachingoptimizer.jl

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,6 +1403,68 @@ function test_pass_nonvariable_constraints()
14031403
return
14041404
end
14051405

1406+
function test_optimize_abstract_callback()
1407+
inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}())
1408+
optimizer = MOI.Utilities.MockOptimizer(inner)
1409+
model = MOI.Utilities.CachingOptimizer(
1410+
MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()),
1411+
optimizer,
1412+
)
1413+
x, _ = MOI.add_constrained_variable(model, MOI.Integer())
1414+
function callback_fn(cb_data)
1415+
_ = MOI.submit(model, MOI.HeuristicSolution(cb_data), [x], [1.0])
1416+
return
1417+
end
1418+
MOI.set(model, MOI.HeuristicCallback(), callback_fn)
1419+
MOI.optimize!(model)
1420+
@test model.state == MOI.Utilities.ATTACHED_OPTIMIZER
1421+
@test optimizer.optimize_called
1422+
return
1423+
end
1424+
1425+
struct ErrorOnSetAttributeModel <: MOI.ModelLike end
1426+
1427+
MOI.is_empty(::ErrorOnSetAttributeModel) = true
1428+
1429+
function MOI.copy_to(::ErrorOnSetAttributeModel, src::MOI.ModelLike)
1430+
return MOI.Utilities.identity_index_map(src)
1431+
end
1432+
1433+
function MOI.set(
1434+
::ErrorOnSetAttributeModel,
1435+
::MOI.ObjectiveSense,
1436+
::MOI.OptimizationSense,
1437+
)
1438+
return error("Something other than unsupported model attribute")
1439+
end
1440+
1441+
function MOI.set(
1442+
::ErrorOnSetAttributeModel,
1443+
::MOI.VariablePrimalStart,
1444+
::MOI.VariableIndex,
1445+
::Float64,
1446+
)
1447+
return error("Something other than unsupported variable attribute")
1448+
end
1449+
1450+
function test_rethrow_set_model_attribute()
1451+
model = MOI.Utilities.CachingOptimizer(
1452+
MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()),
1453+
ErrorOnSetAttributeModel(),
1454+
)
1455+
x = MOI.add_variable(model)
1456+
MOI.Utilities.attach_optimizer(model)
1457+
@test_throws(
1458+
ErrorException("Something other than unsupported model attribute"),
1459+
MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE),
1460+
)
1461+
@test_throws(
1462+
ErrorException("Something other than unsupported variable attribute"),
1463+
MOI.set(model, MOI.VariablePrimalStart(), x, 1.0),
1464+
)
1465+
return
1466+
end
1467+
14061468
end # module
14071469

14081470
TestCachingOptimizer.runtests()

test/Utilities/mockoptimizer.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,28 @@ function test_is_set_by_optimize_optimizer_attribute()
285285
return
286286
end
287287

288+
function test_empty_constructor()
289+
mock = MOI.Utilities.MockOptimizer(Int; supports_names = false)
290+
@test mock.supports_names == false
291+
@test isa(
292+
mock,
293+
MOI.Utilities.MockOptimizer{
294+
MOI.Utilities.UniversalFallback{MOI.Utilities.Model{Int}},
295+
Int,
296+
},
297+
)
298+
mock = MOI.Utilities.MockOptimizer()
299+
@test mock.supports_names
300+
@test isa(
301+
mock,
302+
MOI.Utilities.MockOptimizer{
303+
MOI.Utilities.UniversalFallback{MOI.Utilities.Model{Float64}},
304+
Float64,
305+
},
306+
)
307+
return
308+
end
309+
288310
end # module
289311

290312
TestMockOptimizer.runtests()

test/Utilities/universalfallback.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,8 @@ function test_throw_unsupported_variable_constraint()
434434
MOI.UnsupportedConstraint{typeof(x),typeof(set)}(),
435435
MOI.Utilities.throw_unsupported(model),
436436
)
437+
MOI.delete(model, c)
438+
@test MOI.Utilities.throw_unsupported(model) === nothing
437439
return
438440
end
439441

@@ -447,6 +449,8 @@ function test_throw_unsupported_affine_constraint()
447449
MOI.UnsupportedConstraint{typeof(func),typeof(set)}(),
448450
MOI.Utilities.throw_unsupported(model),
449451
)
452+
MOI.delete(model, c)
453+
@test MOI.Utilities.throw_unsupported(model) === nothing
450454
return
451455
end
452456

@@ -516,6 +520,16 @@ function test_delete_ci_attribute()
516520
return
517521
end
518522

523+
function test_set_inner_constraint_attribute()
524+
inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}())
525+
model = MOI.Utilities.UniversalFallback(inner)
526+
x = MOI.add_variable(model)
527+
c = MOI.add_constraint(model, x, MOI.GreaterThan(1.0))
528+
MOI.set(model, MOI.ConstraintPrimalStart(), c, 1.0)
529+
@test MOI.get(model, MOI.ConstraintPrimalStart(), c) == 1.0
530+
return
531+
end
532+
519533
end # module
520534

521535
TestUniversalFallback.runtests()

0 commit comments

Comments
 (0)