awesome/tests/test-dpi.lua

549 lines
17 KiB
Lua
Raw Permalink Normal View History

-- This testsuite intends to tests the delayed screen creation mode and it's
-- automatic fallback when no screens are created.
local runner = require("_runner")
local ascreen = require("awful.screen")
local gtable = require("gears.table")
local grect = require("gears.geometry").rectangle
local xft_dpi = 42
local fake_viewports, max_id, allow_zero = screen._viewports(), 1, false
local called = 0
local saved_dpi1, saved_dpi2, saved_dpi3
-- Make sure what is tested matches some criteria.
-- Prevents silly errors when adding more test case.
local function validate_viewports(viewports)
for _, a in ipairs(viewports) do
assert(type(a.id) == "number")
assert(a.id > max_id)
assert(type(a.outputs ) == "table")
assert(type(a.geometry) == "table")
for _, prop in ipairs {"x", "y", "width", "height"} do
assert(type(a.geometry[prop]) == "number")
assert(a.geometry[prop] >= 0)
end
max_id = a.id
end
end
local function fake_replace(viewports)
fake_viewports = viewports
screen.emit_signal("property::_viewports", fake_viewports)
end
-- Rollback the clock and replay the initialization.
local function fake_replay(viewports)
if viewports then
validate_viewports(viewports)
end
viewports = viewports or fake_viewports
ascreen._viewports, fake_viewports = {}, viewports
while screen.count() > 0 do
screen[1]:fake_remove()
end
assert(screen.count() == 0)
screen.emit_signal("scanning")
screen.emit_signal("property::_viewports", fake_viewports)
screen.emit_signal("scanned")
assert(screen.count() == #viewports)
assert(type(ascreen._get_xft_dpi()) ~= "boolean")
-- Check of the viewports (+new metadata) is created.
for k, a in ipairs(viewports) do
local s = screen[k]
-- Check if the extra metadata are computed.
assert(s._private.viewport.maximum_dpi)
assert(s._private.viewport.minimum_dpi)
assert(s._private.viewport.preferred_dpi)
assert(s.dpi)
assert(s.maximum_dpi == s._private.viewport.maximum_dpi )
assert(s.minimum_dpi == s._private.viewport.minimum_dpi )
assert(s.preferred_dpi == s._private.viewport.preferred_dpi)
-- Make sure it enters either the main `if` or the fallback one.
assert(s._private.viewport.minimum_dpi ~= math.huge)
assert(s._private.viewport.preferred_dpi ~= math.huge)
-- Check the range.
assert(s._private.viewport.maximum_dpi >= s._private.viewport.minimum_dpi)
assert(s._private.viewport.preferred_dpi >= s._private.viewport.minimum_dpi)
assert(s._private.viewport.preferred_dpi <= s._private.viewport.maximum_dpi)
-- Check if the screen was created using the right viewport
-- (order *is* relevant).
assert(#s._private.viewport.outputs == #a.outputs)
assert(s._private.viewport and s._private.viewport.id == a.id)
end
-- The original shall not be modified, the CAPI for this is read-only.
for _, a in ipairs(fake_viewports) do
assert(not a.minimum_dpi )
assert(not a.maximum_dpi )
assert(not a.preferred_dpi)
assert(not a.dpi )
end
end
local function remove_output(viewport, name)
for k, output in ipairs(viewport.outputs) do
if output.name == name then
table.remove(viewport.outputs, k)
screen.emit_signal("property::_viewports", fake_viewports)
return
end
end
assert(false)
end
local function add_output(viewport, output)
table.insert(viewport.outputs, output)
screen.emit_signal("property::_viewports", fake_viewports)
end
local function remove_viewport(id)
for k, a in ipairs(fake_viewports) do
if a.id == id then
table.remove(fake_viewports, k)
screen.emit_signal("property::_viewports", fake_viewports)
return
end
end
assert(false)
end
local function add_viewport(viewport)
assert(viewport.id)
assert(viewport.geometry)
assert(viewport.outputs)
table.insert(fake_viewports, viewport)
screen.emit_signal("property::_viewports", fake_viewports)
end
local steps = {
-- Monkeypatch for the tests.
function()
-- This should be true for all tests for.
assert(not screen.automatic_factory)
-- Avoids touching the real XRDB, the tests don't control it.
function ascreen._get_xft_dpi()
return xft_dpi
end
-- This testsuite needs to manipulate this.
function ascreen._get_viewports()
local clone = gtable.clone(fake_viewports, true)
assert(#clone > 0 or allow_zero)
return clone
end
return true
end,
-- Remove all the screens, which is **not** supported, but necessary to play
-- with the initial screen creation code.
function()
-- Simple scenario, a single screen.
fake_replay {
{
-- 1 has already been consumed, this makes the test more future proof.
id = 2,
geometry = { x = 0, y = 0, width = 1337, height = 42 },
outputs = {{ name = "leet", mm_width = 353, mm_height = 11 }},
},
}
-- It should honor the XFT DPI when set.
assert(xft_dpi == screen[1].dpi)
-- Now that we know it works, unset it for the other steps.
xft_dpi = nil
-- Check if the "normal" fallback works.
fake_replay()
assert(screen[1].dpi ~= 42)
return true
end,
-- Test with multiple outputs.
function()
-- Simple scenario, a single screen.
fake_replay {
{
-- 1 has already been consumed, this makes the test more future proof.
id = 3,
geometry = { x = 0, y = 0, width = 1337, height = 42 },
outputs = {
{ name = "leet", mm_width = 353 , mm_height = 11 },
{ name = "leet", mm_width = 353/2, mm_height = 11/2 },
{ name = "leet", mm_width = 353/3, mm_height = 11/3 },
},
},
}
assert(screen[1].maximum_dpi == screen[1].minimum_dpi*3)
assert(screen[1].preferred_dpi == screen[1].minimum_dpi )
return true
end,
-- Test with zero outputs.
function()
-- Simple scenario, a single screen.
fake_replay {
{
-- 1 has already been consumed, this makes the test more future proof.
id = 4,
geometry = { x = 0, y = 0, width = 1337, height = 42 },
outputs = {},
},
}
assert(screen[1].maximum_dpi == screen[1].minimum_dpi)
assert(screen[1].preferred_dpi == screen[1].minimum_dpi)
return true
end,
-- Test with 2 screens.
function()
fake_replay {
{
-- 1 has already been consumed, this makes the test more future proof.
id = 5,
geometry = { x = 0, y = 0, width = 1337, height = 42 },
outputs = {{ name = "0x1ee7", mm_width = 353, mm_height = 11 }},
},
{
-- 1 has already been consumed, this makes the test more future proof.
id = 6,
geometry = { x = 1337, y = 0, width = 1337, height = 42 },
outputs = {{ name = "3leet", mm_width = 353, mm_height = 11 }},
},
}
saved_dpi1 = screen[1].preferred_dpi
return true
end,
-- Test with 2 screens with twice the density.
function()
-- Simple scenario, a single screen.
fake_replay {
{
-- 1 has already been consumed, this makes the test more future proof.
id = 7,
geometry = { x = 0, y = 0, width = 1337, height = 42 },
outputs = {{ name = "0x1ee7", mm_width = 353/2, mm_height = 11/2 }},
},
{
-- 1 has already been consumed, this makes the test more future proof.
id = 8,
geometry = { x = 1337, y = 0, width = 1337, height = 42 },
outputs = {{ name = "3leet", mm_width = 353/3, mm_height = 11/3 }},
},
}
-- Test if scaling works as expected.
assert(saved_dpi1*2 == screen[1].preferred_dpi)
assert(saved_dpi1*3 == screen[2].preferred_dpi)
-- Revert to the previous settings if the DPI happens to accidentally match.
-- For the following tests, it has to be different from the fallback.
if screen[1].preferred_dpi == screen[1].dpi then
fake_replay {
{
-- 1 has already been consumed, this makes the test more future proof.
id = 9,
geometry = { x = 0, y = 0, width = 1337, height = 42 },
outputs = {{ name = "0x1ee7", mm_width = 353, mm_height = 11 }},
}
}
end
saved_dpi1 = screen[1].preferred_dpi
-- The next test requires a different value.
assert(saved_dpi1 ~= screen[1].dpi)
-- Enable autodpi.
ascreen.set_auto_dpi_enabled(true)
return true
end,
-- Test if autodpi does something.
function()
-- Replay with the same settings.
fake_replay()
-- If this isn't true, then auto-dpi didn't do its job.
assert(screen[1].dpi == saved_dpi1)
-- Revert to a single viewport for the next tests.
fake_replay {
{
-- 1 has already been consumed, this makes the test more future proof.
id = 10,
geometry = { x = 0, y = 0, width = 1337, height = 42 },
outputs = {{ name = "leet", mm_width = 353, mm_height = 11 }},
},
}
saved_dpi1 = screen[1].dpi
saved_dpi2 = screen[1].maximum_dpi
saved_dpi3 = screen[1].minimum_dpi
return true
end,
-- Test adding an output.
function()
local viewport = screen[1]._private.viewport
add_output(fake_viewports[1], {
name = "foobar",
mm_width = 353/2,
mm_height = 11/2
})
add_output(fake_viewports[1], {
name = "foobar2",
mm_width = 353*2,
mm_height = 11*2
})
-- It should have been kept.
assert(viewport == screen[1]._private.viewport)
-- If this isn't true, then auto-dpi didn't do its job.
assert(screen[1].dpi ~= saved_dpi1)
-- Now that there is multiple DPIs for the same viewport, the number
-- should double.
assert(#screen[1]._private.viewport.outputs == 3)
assert(screen[1].maximum_dpi == saved_dpi2*2)
assert(screen[1].minimum_dpi == saved_dpi3/2)
assert(screen[1].dpi == saved_dpi1/2)
remove_output(fake_viewports[1], "leet")
assert(#screen[1]._private.viewport.outputs == 2)
remove_output(fake_viewports[1], "foobar")
-- At this point, only 1 DPI is left.
assert(#screen[1]._private.viewport.outputs == 1)
assert(screen[1].maximum_dpi == saved_dpi1/2)
assert(screen[1].minimum_dpi == saved_dpi1/2)
assert(screen[1].dpi == saved_dpi1/2)
return true
end,
-- Test adding/removing viewports.
function()
assert(screen.count() == 1)
add_viewport {
id = 11,
geometry = { x = 1337, y = 0, width = 1337, height = 42 },
outputs = {{
name = "foobar",
mm_width = 353/2,
mm_height = 11/2
}}
}
assert(screen.count() == 2)
assert(screen[1]._private.viewport.id == 10)
assert(screen[2]._private.viewport.id == 11)
assert(grect.are_equal(screen[1]._private.viewport.geometry, screen[1].geometry))
assert(grect.are_equal(screen[2]._private.viewport.geometry, screen[2].geometry))
assert(#ascreen._viewports == 2)
remove_viewport(10)
assert(#ascreen._viewports == 1)
assert(screen.count() == 1)
assert(screen[1]._private.viewport.id == 11)
assert(grect.are_equal(screen[1]._private.viewport.geometry, screen[1].geometry))
return true
end,
-- Test resizing.
function()
local s, sa = screen[1], screen[1]._private.viewport
assert(screen.count() == 1)
assert(#ascreen._viewports == 1)
-- First, to the same size (replace internal screen with external screen).
-- It may or may not create a different viewport in practice, but it's possible
-- if the first screen is removed then the new one added in 2 steps.
fake_replace {
{
id = 12,
geometry = { x = 1337, y = 0, width = 1337, height = 42 },
outputs = {{ name = "foobar3", mm_width = 353/2, mm_height = 11/2}}
}
}
assert(screen.count() == 1)
assert(s == screen[1])
assert(s._private.viewport ~= sa)
assert(s._private.viewport.id == 12)
-- Now 2 smaller (resolution) screens side by side to make sure it doesn't
-- go haywire with overlapping
fake_replace {
{
id = 13,
geometry = { x = 1337, y = 0, width = 680, height = 42 },
outputs = {{ name = "foobar4", mm_width = 353/2, mm_height = 11/2}}
},
{
id = 14,
geometry = { x = 1337+680, y = 0, width = 1337, height = 42 },
outputs = {{ name = "foobar5", mm_width = 353/2, mm_height = 11/2}}
}
}
assert(screen.count() == 2)
assert(s == screen[1])
assert(s._private.viewport.id == 13)
assert(s.geometry.x == 1337)
assert(s.geometry.width == 680)
-- Disconnect the default handler to test the fallback.
screen.disconnect_signal("request::create", ascreen.create_screen_handler)
screen.disconnect_signal("request::remove", ascreen.remove_screen_handler)
screen.disconnect_signal("request::resize", ascreen.resize_screen_handler)
return true
end,
-- Test the fallback screen creation.
function()
fake_replay {
{
-- 1 has already been consumed, this makes the test more future proof.
id = 15,
geometry = { x = 0, y = 0, width = 1337, height = 42 },
outputs = {{ name = "0x1ee7", mm_width = 353, mm_height = 11 }},
},
{
-- 1 has already been consumed, this makes the test more future proof.
id = 16,
geometry = { x = 1337, y = 0, width = 1337, height = 42 },
outputs = {{ name = "3leet", mm_width = 353, mm_height = 11 }},
},
}
assert(screen.count() == 2)
assert(screen[1]._private.viewport.id == 15)
assert(screen[2]._private.viewport.id == 16)
-- Connect custom handler and see if the internals accidently depend on
-- implementation details.
screen.connect_signal("request::create", function(viewport)
assert(viewport.minimum_dpi)
assert(viewport.maximum_dpi)
assert(viewport.preferred_dpi)
local geo = viewport.geometry
local s = screen.fake_add(geo.x, geo.y, geo.width, geo.height)
s.outputs = viewport.outputs
called = called + 1
end)
screen.connect_signal("request::remove", function(viewport)
local geo = viewport.geometry
for s in screen do
if grect.are_equal(geo, s.geometry) then
s:fake_remove()
called = called + 1
return
end
end
end)
return true
end,
-- Test if alternate implementations don't explode the internals.
function()
ascreen._viewports = {}
while screen.count() > 0 do
screen[1]:fake_remove()
end
assert(screen.count() == 0)
-- screen.emit_signal("scanning")
screen.emit_signal("property::_viewports", fake_viewports)
screen.emit_signal("scanned")
assert(screen.count() == 2)
assert(grect.are_equal(
screen[1].geometry, {x = 0, y = 0, width = 1337, height = 42}
))
assert(grect.are_equal(
screen[2].geometry, {x = 1337, y = 0, width = 1337, height = 42}
))
-- Call the DPI properties just to check it doesn't cause an error)
assert(screen[1].dpi or true)
assert(screen[1].maximum_dpi or true)
assert(screen[1].minimum_dpi or true)
assert(screen[1].preferred_dpi or true)
assert(screen[2].dpi or true)
assert(screen[2].maximum_dpi or true)
assert(screen[2].minimum_dpi or true)
assert(screen[2].preferred_dpi or true)
assert(called == 2)
-- Try adding an viewport.
table.insert(fake_viewports, {
-- 1 has already been consumed, this makes the test more future proof.
id = 17,
geometry = { x = 1337, y = 42, width = 1337, height = 42 },
outputs = {{ name = "last", mm_width = 353, mm_height = 11 }},
})
screen.emit_signal("property::_viewports", fake_viewports)
assert(screen.count() == 3)
assert(called == 3)
assert(grect.are_equal(
screen[3].geometry, {x = 1337, y = 42, width = 1337, height = 42}
))
-- Remove the middle one.
table.remove(fake_viewports, 2)
screen.emit_signal("property::_viewports", fake_viewports)
assert(screen.count() == 2)
assert(called == 4)
assert(grect.are_equal(
screen[1].geometry, {x = 0, y = 0, width = 1337, height = 42}
))
assert(grect.are_equal(
screen[2].geometry, {x = 1337, y = 42, width = 1337, height = 42}
))
return true
end
}
runner.run_steps(steps)