-
Notifications
You must be signed in to change notification settings - Fork 87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: unit tests #329
RFC: unit tests #329
Changes from 7 commits
faee6d9
fb97f1f
10f8cfd
e89135c
b04d858
710510c
c387d55
496b98d
218d5bc
026c0e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#= | ||
These tests aim to minimally test each expected feature in MOI, in addition | ||
to the full end-to-end tests in contlinear.jl etc | ||
=# | ||
|
||
const atomictests = Dict{String, Function}() | ||
|
||
include("variables.jl") | ||
include("objectives.jl") | ||
include("constraints.jl") | ||
|
||
@moitestset atomic |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
""" | ||
Test getting constraints by name. | ||
""" | ||
function getconstraint(model::MOI.ModelLike, config::TestConfig) | ||
MOI.empty!(model) | ||
MOIU.loadfromstring!(model,""" | ||
variables: x | ||
minobjective: 2.0x | ||
c1: x >= 1.0 | ||
c2: x <= 2.0 | ||
""") | ||
@test !MOI.canget(model, MOI.ConstraintIndex, "c3") | ||
@test MOI.canget(model, MOI.ConstraintIndex, "c1") | ||
@test MOI.canget(model, MOI.ConstraintIndex{MOI.SingleVariable, MOI.GreaterThan{Float64}}, "c1") | ||
@test !MOI.canget(model, MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}, "c1") | ||
@test MOI.canget(model, MOI.ConstraintIndex, "c2") | ||
@test !MOI.canget(model, MOI.ConstraintIndex{MOI.SingleVariable, MOI.GreaterThan{Float64}}, "c2") | ||
@test MOI.canget(model, MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}, "c2") | ||
c1 = MOI.get(model, MOI.ConstraintIndex{MOI.SingleVariable, MOI.GreaterThan{Float64}}, "c1") | ||
@test MOI.isvalid(model, c1) | ||
c2 = MOI.get(model, MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}, "c2") | ||
@test MOI.isvalid(model, c2) | ||
end | ||
atomictests["getconstraint"] = getconstraint |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
#= | ||
Functions in this file test functionality relating to objectives in MOI. | ||
|
||
### Requires | ||
- optimize! | ||
|
||
### Functionality currently tested | ||
- get/set ObjectiveSense | ||
- a constant in a affine objective | ||
- a blank objective | ||
|
||
### Functionality not yet tested | ||
- Quadratic Objectives | ||
- Modifications | ||
=# | ||
|
||
""" | ||
Set objective to MaxSense | ||
""" | ||
function max_sense(model::MOI.ModelLike, config::TestConfig) | ||
MOI.empty!(model) | ||
@test MOI.isempty(model) | ||
@test MOI.canset(model, MOI.ObjectiveSense()) | ||
MOI.set!(model, MOI.ObjectiveSense(), MOI.MaxSense) | ||
@test MOI.canget(model, MOI.ObjectiveSense()) | ||
@test MOI.get(model, MOI.ObjectiveSense()) == MOI.MaxSense | ||
end | ||
atomictests["max_sense"] = max_sense | ||
|
||
""" | ||
Set objective to MinSense | ||
""" | ||
function min_sense(model::MOI.ModelLike, config::TestConfig) | ||
MOI.empty!(model) | ||
@test MOI.isempty(model) | ||
@test MOI.canset(model, MOI.ObjectiveSense()) | ||
MOI.set!(model, MOI.ObjectiveSense(), MOI.MinSense) | ||
@test MOI.canget(model, MOI.ObjectiveSense()) | ||
@test MOI.get(model, MOI.ObjectiveSense()) == MOI.MinSense | ||
end | ||
atomictests["min_sense"] = min_sense | ||
|
||
""" | ||
Set objective to FeasibilitySense | ||
""" | ||
function feasibility_sense(model::MOI.ModelLike, config::TestConfig) | ||
MOI.empty!(model) | ||
@test MOI.isempty(model) | ||
@test MOI.canset(model, MOI.ObjectiveSense()) | ||
MOI.set!(model, MOI.ObjectiveSense(), MOI.FeasibilitySense) | ||
@test MOI.canget(model, MOI.ObjectiveSense()) | ||
@test MOI.get(model, MOI.ObjectiveSense()) == MOI.FeasibilitySense | ||
end | ||
atomictests["feasibility_sense"] = feasibility_sense | ||
|
||
""" | ||
Test constant in objective. | ||
""" | ||
function constant_obj(model::MOI.ModelLike, config::TestConfig) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the test calls |
||
atol, rtol = config.atol, config.rtol | ||
MOI.empty!(model) | ||
@test MOI.isempty(model) | ||
MOIU.loadfromstring!(model,""" | ||
variables: x | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a great use of |
||
minobjective: 2.0x + 1.0 | ||
c: x >= 1.0 | ||
""") | ||
MOI.optimize!(model) | ||
@test MOI.get(model, MOI.ObjectiveValue()) ≈ 3.0 atol=atol rtol=rtol | ||
end | ||
atomictests["constant_obj"] = constant_obj | ||
|
||
""" | ||
Test blank objective. | ||
""" | ||
function blank_obj(model::MOI.ModelLike, config::TestConfig) | ||
atol, rtol = config.atol, config.rtol | ||
MOI.empty!(model) | ||
@test MOI.isempty(model) | ||
MOIU.loadfromstring!(model,""" | ||
variables: x | ||
minobjective: 0.0x + 0.0 | ||
c: x >= 1.0 | ||
""") | ||
MOI.optimize!(model) | ||
@test MOI.get(model, MOI.ObjectiveValue()) ≈ 0.0 atol=atol rtol=rtol | ||
end | ||
atomictests["blank_obj"] = blank_obj | ||
|
||
""" | ||
Test SingleVariable objective. | ||
""" | ||
function singlevariable_obj(model::MOI.ModelLike, config::TestConfig) | ||
atol, rtol = config.atol, config.rtol | ||
MOI.empty!(model) | ||
@test MOI.isempty(model) | ||
MOIU.loadfromstring!(model,""" | ||
variables: x | ||
minobjective: x | ||
c: x >= 1.0 | ||
""") | ||
MOI.optimize!(model) | ||
@test MOI.get(model, MOI.ObjectiveValue()) ≈ 1.0 atol=atol rtol=rtol | ||
end | ||
atomictests["singlevariable_obj"] = singlevariable_obj |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
#= | ||
Functions in this file test functionality relating to variables in MOI. | ||
|
||
### Functionality currently tested | ||
- canaddvariable | ||
- addvariables! | ||
- addvariable! | ||
- deleting variables | ||
- get/set! VariableName | ||
- isvalid for VariableIndex | ||
- get VariableIndex by name | ||
- NumberOfVariables | ||
|
||
### Functionality not yet tested | ||
- VariablePrimalStart | ||
- VariablePrimal | ||
- VariableBasisStatus | ||
- ListOfVariableIndices | ||
=# | ||
|
||
""" | ||
This function tests adding a single variable. | ||
""" | ||
function add_variable(model::MOI.ModelLike, config::TestConfig) | ||
MOI.empty!(model) | ||
@test MOI.isempty(model) | ||
@test MOI.canaddvariable(model) | ||
@test MOI.get(model, MOI.NumberOfVariables()) == 0 | ||
v = MOI.addvariable!(model) | ||
@test MOI.get(model, MOI.NumberOfVariables()) == 1 | ||
end | ||
atomictests["add_variable"] = add_variable | ||
|
||
""" | ||
This function tests adding multiple variables. | ||
""" | ||
function add_variables(model::MOI.ModelLike, config::TestConfig) | ||
MOI.empty!(model) | ||
@test MOI.isempty(model) | ||
@test MOI.canaddvariable(model) | ||
@test MOI.get(model, MOI.NumberOfVariables()) == 0 | ||
v = MOI.addvariables!(model, 2) | ||
@test MOI.get(model, MOI.NumberOfVariables()) == 2 | ||
end | ||
atomictests["add_variables"] = add_variables | ||
|
||
""" | ||
This function tests adding, and then deleting, | ||
a single variable. | ||
""" | ||
function delete_variable(model::MOI.ModelLike, config::TestConfig) | ||
MOI.empty!(model) | ||
@test MOI.isempty(model) | ||
@test MOI.canaddvariable(model) | ||
@test MOI.get(model, MOI.NumberOfVariables()) == 0 | ||
v = MOI.addvariable!(model) | ||
@test MOI.get(model, MOI.NumberOfVariables()) == 1 | ||
@test MOI.candelete(model, v) | ||
MOI.delete!(model, v) | ||
@test MOI.get(model, MOI.NumberOfVariables()) == 0 | ||
end | ||
atomictests["delete_variable"] = delete_variable | ||
|
||
""" | ||
This function tests adding, and then deleting, | ||
multiple variables. | ||
""" | ||
function delete_variables(model::MOI.ModelLike, config::TestConfig) | ||
MOI.empty!(model) | ||
@test MOI.isempty(model) | ||
@test MOI.canaddvariable(model) | ||
@test MOI.get(model, MOI.NumberOfVariables()) == 0 | ||
v = MOI.addvariables!(model, 2) | ||
@test MOI.get(model, MOI.NumberOfVariables()) == 2 | ||
@test MOI.candelete(model, v) | ||
MOI.delete!(model, v) | ||
@test MOI.get(model, MOI.NumberOfVariables()) == 0 | ||
v = MOI.addvariables!(model, 2) | ||
@test MOI.get(model, MOI.NumberOfVariables()) == 2 | ||
@test MOI.candelete(model, v[1]) | ||
MOI.delete!(model, v[1]) | ||
@test MOI.get(model, MOI.NumberOfVariables()) == 1 | ||
@test !MOI.candelete(model, v[1]) | ||
@test MOI.candelete(model, v[2]) | ||
@test !MOI.isvalid(model, v[1]) | ||
@test MOI.isvalid(model, v[2]) | ||
end | ||
atomictests["delete_variables"] = delete_variable | ||
|
||
""" | ||
Test getting variables by name. | ||
""" | ||
function getvariable(model::MOI.ModelLike, config::TestConfig) | ||
MOI.empty!(model) | ||
MOIU.loadfromstring!(model,""" | ||
variables: x | ||
minobjective: 2.0x | ||
c1: x >= 1.0 | ||
c2: x <= 2.0 | ||
""") | ||
@test MOI.canget(model, MOI.VariableIndex, "x") | ||
@test !MOI.canget(model, MOI.VariableIndex, "y") | ||
x = MOI.get(model, MOI.VariableIndex, "x") | ||
@test MOI.isvalid(model, x) | ||
end | ||
atomictests["getvariable"] = getvariable | ||
|
||
""" | ||
Test getting and setting varaible names. | ||
""" | ||
function variablenames(model::MOI.ModelLike, config::TestConfig) | ||
MOI.empty!(model) | ||
v = MOI.addvariable!(model) | ||
@test MOI.get(model, MOI.VariableName(), v) == "" | ||
@test MOI.canset(model, MOI.VariableName(), typeof(v)) | ||
MOI.set!(model, MOI.VariableName(), v, "x") | ||
@test MOI.get(model, MOI.VariableName(), v) == "x" | ||
MOI.set!(model, MOI.VariableName(), v, "y") | ||
@test MOI.get(model, MOI.VariableName(), v) == "y" | ||
x = MOI.addvariable!(model) | ||
MOI.set!(model, MOI.VariableName(), x, "x") | ||
@test MOI.get(model, MOI.VariableName(), x) == "x" | ||
end | ||
atomictests["variablenames"] = variablenames | ||
|
||
""" | ||
Test the setting of an upper bound | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another example where "solve" in the name would be informative, e.g., |
||
""" | ||
function upperbound(model::MOI.ModelLike, config::TestConfig) | ||
atol, rtol = config.atol, config.rtol | ||
MOI.empty!(model) | ||
@test MOI.isempty(model) | ||
MOIU.loadfromstring!(model,""" | ||
variables: x | ||
maxobjective: 2.0x | ||
c1: x <= 1.0 | ||
c2: x >= 0.0 | ||
""") | ||
MOI.optimize!(model) | ||
@test MOI.get(model, MOI.PrimalStatus()) == MOI.FeasiblePoint | ||
v = MOI.get(model, MOI.VariableIndex, "x") | ||
@test MOI.get(model, MOI.VariablePrimal(), v) ≈ 1 atol=atol rtol=rtol | ||
if config.duals | ||
@test MOI.get(model, MOI.DualStatus()) == MOI.FeasiblePoint | ||
c1 = MOI.get(model, MOI.ConstraintIndex{MOI.SingleVariable,MOI.LessThan{Float64}}, "c1") | ||
@test MOI.get(model, MOI.ConstraintDual(), c1) ≈ -2.0 atol=atol rtol=rtol | ||
c2 = MOI.get(model, MOI.ConstraintIndex{MOI.SingleVariable,MOI.GreaterThan{Float64}}, "c2") | ||
@test MOI.get(model, MOI.ConstraintDual(), c2) ≈ 0.0 atol=atol rtol=rtol | ||
end | ||
end | ||
atomictests["upperbound"] = upperbound | ||
|
||
""" | ||
Test the setting of an lower bound | ||
""" | ||
function lowerbound(model::MOI.ModelLike, config::TestConfig) | ||
atol, rtol = config.atol, config.rtol | ||
MOI.empty!(model) | ||
@test MOI.isempty(model) | ||
MOIU.loadfromstring!(model,""" | ||
variables: x | ||
minobjective: 2.0x | ||
c1: x >= 1.0 | ||
c2: x <= 2.0 | ||
""") | ||
MOI.optimize!(model) | ||
@test MOI.get(model, MOI.PrimalStatus()) == MOI.FeasiblePoint | ||
v = MOI.get(model, MOI.VariableIndex, "x") | ||
@test MOI.get(model, MOI.VariablePrimal(), v) ≈ 1 atol=atol rtol=rtol | ||
if config.duals | ||
@test MOI.get(model, MOI.DualStatus()) == MOI.FeasiblePoint | ||
c1 = MOI.get(model, MOI.ConstraintIndex{MOI.SingleVariable,MOI.GreaterThan{Float64}}, "c1") | ||
@test MOI.get(model, MOI.ConstraintDual(), c1) ≈ 2.0 atol=atol rtol=rtol | ||
c2 = MOI.get(model, MOI.ConstraintIndex{MOI.SingleVariable,MOI.LessThan{Float64}}, "c2") | ||
@test MOI.get(model, MOI.ConstraintDual(), c2) ≈ 0.0 atol=atol rtol=rtol | ||
end | ||
end | ||
atomictests["lowerbound"] = lowerbound |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's weird that we have to call
MOI.empty!
at the beginning of every test. This should happen somewhere else.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. Maybe it should go here?
https://github.com/JuliaOpt/MathOptInterface.jl/blob/84c5b19fa7cea292b715f6e02658bf977db08134/src/Test/config.jl#L42-L43
That can be a job for a different PR.