From e683c0b07928d9b51505477c85dfd8dc9838ecbc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Aug 2016 21:19:28 +0200 Subject: [PATCH] add tests for parsing certain xrandr output; fix crash when screen doesn't have an EDID --- lilass | 14 +--- screen.py | 21 +++-- tests.py | 25 ++++-- xrandr-tests/no-EDID | 136 +++++++++++++++++++++++++++++++++ xrandr-tests/with-extern | 160 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 331 insertions(+), 25 deletions(-) create mode 100644 xrandr-tests/no-EDID create mode 100644 xrandr-tests/with-extern diff --git a/lilass b/lilass index 6780879..3512a5f 100755 --- a/lilass +++ b/lilass @@ -22,14 +22,6 @@ import gui, screen, util, database frontend = gui.getFrontend("cli") # the fallback, until we got a proper frontend. This is guaranteed to be available. cmdArgs = None -# for auto-config: common names of internal connectors -commonInternalConnectorPrefixes = ['LVDS', 'eDP'] -commonInternalConnectorSuffices = ['', '0', '1', '-0', '-1'] -def commonInternalConnectorNames(): - for prefix in commonInternalConnectorPrefixes: - for suffix in commonInternalConnectorSuffices: - yield prefix+suffix - # Load a section-less config file: maps parameter names to space-separated lists of strings (with shell quotation) def loadConfigFile(filename): import shlex @@ -74,7 +66,7 @@ def situationByConfig(config): raise Exception("You must specify exactly one internal connector.") internalConnectors = config['internalConnector'] else: - internalConnectors = commonInternalConnectorNames() + internalConnectors = screen.commonInternalConnectorNames() # run! return screen.ScreenSituation(internalConnectors, config.get('externalConnectors')) @@ -160,9 +152,9 @@ if __name__ == "__main__": setup = screen.ScreenSetup(intResolution = None, extResolution = situation.externalConnector.getPreferredResolution()) elif cmdArgs.rel_position is not None: # construct automatically, based on CLI arguments - # first, figure out the desired RelativeScreenPosition... waht a bad hack... + # first, figure out the desired RelativeScreenPosition... what a bad hack... relPos = list(filter(lambda relPosItem: relPosFilter(relPosItem[0]) == cmdArgs.rel_position, screen.RelativeScreenPosition.__members__.items())) - assert len(relPos) == 1, "CLI argument is ambigue" + assert len(relPos) == 1, "CLI argument is ambiguous" relPos = relPos[0][1] # now we construct the ScreenSetup if relPos == screen.RelativeScreenPosition.MIRROR: diff --git a/screen.py b/screen.py index 133e333..f0de7e9 100644 --- a/screen.py +++ b/screen.py @@ -32,6 +32,14 @@ def processOutputGen(*args): def processOutputIt(*args): return list(processOutputGen(*args)) # list() iterates over the generator +# for auto-config: common names of internal connectors +def commonInternalConnectorNames(): + commonInternalConnectorPrefixes = ['LVDS', 'eDP'] + commonInternalConnectorSuffices = ['', '0', '1', '-0', '-1'] + for prefix in commonInternalConnectorPrefixes: + for suffix in commonInternalConnectorSuffices: + yield prefix+suffix + ## the classes class RelativeScreenPosition(Enum): @@ -153,7 +161,7 @@ class ScreenSetup: class Connector: def __init__(self, name=None): self.name = name # connector name, e.g. "HDMI1" - self.edid = None # EDID string for the connector, or None if disconnected + self.edid = None # EDID string for the connector, or None if disconnected / unavailable self._resolutions = set() # set of Resolution objects, empty if disconnected self._preferredResolution = None self.previousResolution = None @@ -166,8 +174,8 @@ class Connector: return """""" % (str(self.name), str(self.edid), ", ".join(str(r) for r in self.getResolutionList())) def isConnected(self): - assert (self.edid is None) == (len(self._resolutions)==0), "Resolution-EDID mismatch; #resolutions: {}".format(len(self._resolutions)) - return self.edid is not None + # It is very possible not to have an EDID even for a connected connector + return len(self._resolutions) > 0 def addResolution(self, resolution): assert isinstance(resolution, Resolution) @@ -192,7 +200,7 @@ class Connector: return sorted(self._resolutions, key=lambda r: -r.pixelCount()) class ScreenSituation: - connectors = [] # contains all the Connector objects + connectors = None # contains all the Connector objects internalConnector = None # the internal Connector object (will be an enabled one) externalConnector = None # the used external Connector object (an enabled one), or None previousSetup = None # None or the ScreenSetup used the last time this external screen was connected @@ -202,6 +210,7 @@ class ScreenSituation: '''Both arguments are lists of connector names. The first one which exists and has a screen attached is chosen for that class. can be None to just choose any remaining connector.''' # which connectors are there? + self.connectors = [] self._getXrandrInformation(xrandrSource) # figure out which is the internal connector self.internalConnector = self._findAvailableConnector(internalConnectorNames) @@ -223,7 +232,7 @@ class ScreenSituation: readingEdid = False if xrandrSource is None: xrandrSource = processOutputGen("xrandr", "-q", "--verbose") - for line in processOutputGen("xrandr", "-q", "--verbose"): + for line in xrandrSource: if readingEdid: m = re.match(r'^\s*([0-9a-f]+)\s*$', line) if m is not None: @@ -241,7 +250,7 @@ class ScreenSituation: m = re.search(r'^([\w\-]+) (dis)?connected ', line) if m is not None: connector = Connector(m.group(1)) - assert not any(c.name == connector.name for c in self.connectors) + assert not any(c.name == connector.name for c in self.connectors), "Duplicate connector {}".format(connector.name) if not connector.name.startswith("VIRTUAL"): # skip "VIRTUAL" connectors self.connectors.append(connector) diff --git a/tests.py b/tests.py index 9f3fb46..3ce9fa8 100755 --- a/tests.py +++ b/tests.py @@ -1,17 +1,26 @@ #!/usr/bin/env python3 import unittest import screen +import os class TestResolutions(unittest.TestCase): - def test_ratio(self): - # check whether a few aspect ratios are printed as expected - self.assertEqual(str(screen.Resolution(1024, 768)), '1024x768 (4:3)') - self.assertTrue(str(screen.Resolution(1280, 1024)) in ('1280x1024 (5:4)', '1280x1024 (4:3)')) - self.assertEqual(str(screen.Resolution(1366, 768)), '1366x768 (16:9)') - self.assertEqual(str(screen.Resolution(1920, 1080)), '1920x1080 (16:9)') - self.assertEqual(str(screen.Resolution(1920, 1200)), '1920x1200 (16:10)') - self.assertEqual(str(screen.Resolution(720, 480)), '720x480 (3:2)') + def test_ratio(self): + # check whether a few aspect ratios are printed as expected + self.assertEqual(str(screen.Resolution(1024, 768)), '1024x768 (4:3)') + self.assertTrue(str(screen.Resolution(1280, 1024)) in ('1280x1024 (5:4)', '1280x1024 (4:3)')) + self.assertEqual(str(screen.Resolution(1366, 768)), '1366x768 (16:9)') + self.assertEqual(str(screen.Resolution(1920, 1080)), '1920x1080 (16:9)') + self.assertEqual(str(screen.Resolution(1920, 1200)), '1920x1200 (16:10)') + self.assertEqual(str(screen.Resolution(720, 480)), '720x480 (3:2)') + + def test_xrandr(self): + internalConnectors = list(screen.commonInternalConnectorNames()) + for file in os.listdir('xrandr-tests'): + print("##",file) + with open(os.path.join('xrandr-tests', file)) as file: + s = screen.ScreenSituation(internalConnectors, xrandrSource = file) + del(s) if __name__ == '__main__': unittest.main() diff --git a/xrandr-tests/no-EDID b/xrandr-tests/no-EDID new file mode 100644 index 0000000..36eb9fb --- /dev/null +++ b/xrandr-tests/no-EDID @@ -0,0 +1,136 @@ +Screen 0: minimum 8 x 8, current 1366 x 768, maximum 32767 x 32767 +LVDS1 connected 1366x768+0+0 (0x48) normal (normal left inverted right x axis y axis) 344mm x 194mm + Identifier: 0x42 + Timestamp: 30808024 + Subpixel: horizontal rgb + Gamma: 1.0:1.0:1.0 + Brightness: 1.0 + Clones: + CRTC: 0 + CRTCs: 0 1 + Transform: 1.000000 0.000000 0.000000 + 0.000000 1.000000 0.000000 + 0.000000 0.000000 1.000000 + filter: + EDID: + 00ffffffffffff0030e4e30200000000 + 00140103802213780aa9059f5e589c26 + 19505400000001010101010101010101 + 010101010101581b567e50000e302430 + 350058c2100000190000000000000000 + 00000000000000000000000000fe004c + 4720446973706c61790a2020000000fe + 004c503135365748342d544c42310071 + BACKLIGHT: 4216 + range: (0, 4882) + Backlight: 4216 + range: (0, 4882) + scaling mode: Full aspect + supported: None, Full, Center, Full aspect + 1366x768 (0x48) 70.000MHz -HSync -VSync *current +preferred + h: width 1366 start 1402 end 1450 total 1492 skew 0 clock 46.92KHz + v: height 768 start 771 end 776 total 782 clock 60.00Hz + 1360x768 (0xd1) 84.750MHz -HSync +VSync + h: width 1360 start 1432 end 1568 total 1776 skew 0 clock 47.72KHz + v: height 768 start 771 end 781 total 798 clock 59.80Hz + 1360x768 (0xd2) 72.000MHz +HSync -VSync + h: width 1360 start 1408 end 1440 total 1520 skew 0 clock 47.37KHz + v: height 768 start 771 end 781 total 790 clock 59.96Hz + 1280x720 (0xd3) 74.480MHz -HSync +VSync + h: width 1280 start 1336 end 1472 total 1664 skew 0 clock 44.76KHz + v: height 720 start 721 end 724 total 746 clock 60.00Hz + 1024x768 (0xd4) 65.000MHz -HSync -VSync + h: width 1024 start 1048 end 1184 total 1344 skew 0 clock 48.36KHz + v: height 768 start 771 end 777 total 806 clock 60.00Hz + 1024x576 (0xd5) 46.995MHz -HSync +VSync + h: width 1024 start 1064 end 1168 total 1312 skew 0 clock 35.82KHz + v: height 576 start 577 end 580 total 597 clock 60.00Hz + 960x540 (0xd6) 40.784MHz -HSync +VSync + h: width 960 start 992 end 1088 total 1216 skew 0 clock 33.54KHz + v: height 540 start 541 end 544 total 559 clock 60.00Hz + 800x600 (0xd7) 40.000MHz +HSync +VSync + h: width 800 start 840 end 968 total 1056 skew 0 clock 37.88KHz + v: height 600 start 601 end 605 total 628 clock 60.32Hz + 800x600 (0xd8) 36.000MHz +HSync +VSync + h: width 800 start 824 end 896 total 1024 skew 0 clock 35.16KHz + v: height 600 start 601 end 603 total 625 clock 56.25Hz + 864x486 (0xd9) 32.901MHz -HSync +VSync + h: width 864 start 888 end 976 total 1088 skew 0 clock 30.24KHz + v: height 486 start 487 end 490 total 504 clock 60.00Hz + 640x480 (0xda) 25.175MHz -HSync -VSync + h: width 640 start 656 end 752 total 800 skew 0 clock 31.47KHz + v: height 480 start 490 end 492 total 525 clock 59.94Hz + 720x405 (0xdb) 22.176MHz -HSync +VSync + h: width 720 start 728 end 800 total 880 skew 0 clock 25.20KHz + v: height 405 start 406 end 409 total 420 clock 60.00Hz + 680x384 (0xdc) 19.677MHz -HSync +VSync + h: width 680 start 688 end 752 total 824 skew 0 clock 23.88KHz + v: height 384 start 385 end 388 total 398 clock 60.00Hz + 640x360 (0xdd) 17.187MHz -HSync +VSync + h: width 640 start 640 end 704 total 768 skew 0 clock 22.38KHz + v: height 360 start 361 end 364 total 373 clock 60.00Hz +DP1 disconnected (normal left inverted right x axis y axis) + Identifier: 0x43 + Timestamp: 30808024 + Subpixel: unknown + Clones: + CRTCs: 0 1 + Transform: 1.000000 0.000000 0.000000 + 0.000000 1.000000 0.000000 + 0.000000 0.000000 1.000000 + filter: + Broadcast RGB: Automatic + supported: Automatic, Full, Limited 16:235 + audio: auto + supported: force-dvi, off, auto, on +HDMI1 disconnected primary (normal left inverted right x axis y axis) + Identifier: 0x44 + Timestamp: 30808024 + Subpixel: unknown + Clones: VGA1 + CRTCs: 0 1 + Transform: 1.000000 0.000000 0.000000 + 0.000000 1.000000 0.000000 + 0.000000 0.000000 1.000000 + filter: + aspect ratio: Automatic + supported: Automatic, 4:3, 16:9 + Broadcast RGB: Automatic + supported: Automatic, Full, Limited 16:235 + audio: auto + supported: force-dvi, off, auto, on +VGA1 connected (normal left inverted right x axis y axis) + Identifier: 0x45 + Timestamp: 30808024 + Subpixel: unknown + Clones: HDMI1 + CRTCs: 0 1 + Transform: 1.000000 0.000000 0.000000 + 0.000000 1.000000 0.000000 + 0.000000 0.000000 1.000000 + filter: + 1024x768 (0xd4) 65.000MHz -HSync -VSync + h: width 1024 start 1048 end 1184 total 1344 skew 0 clock 48.36KHz + v: height 768 start 771 end 777 total 806 clock 60.00Hz + 800x600 (0xd7) 40.000MHz +HSync +VSync + h: width 800 start 840 end 968 total 1056 skew 0 clock 37.88KHz + v: height 600 start 601 end 605 total 628 clock 60.32Hz + 800x600 (0xd8) 36.000MHz +HSync +VSync + h: width 800 start 824 end 896 total 1024 skew 0 clock 35.16KHz + v: height 600 start 601 end 603 total 625 clock 56.25Hz + 848x480 (0x208) 33.750MHz +HSync +VSync + h: width 848 start 864 end 976 total 1088 skew 0 clock 31.02KHz + v: height 480 start 486 end 494 total 517 clock 60.00Hz + 640x480 (0xda) 25.175MHz -HSync -VSync + h: width 640 start 656 end 752 total 800 skew 0 clock 31.47KHz + v: height 480 start 490 end 492 total 525 clock 59.94Hz +VIRTUAL1 disconnected (normal left inverted right x axis y axis) + Identifier: 0x46 + Timestamp: 30808024 + Subpixel: no subpixels + Clones: + CRTCs: 2 + Transform: 1.000000 0.000000 0.000000 + 0.000000 1.000000 0.000000 + 0.000000 0.000000 1.000000 + filter: diff --git a/xrandr-tests/with-extern b/xrandr-tests/with-extern new file mode 100644 index 0000000..19c99e5 --- /dev/null +++ b/xrandr-tests/with-extern @@ -0,0 +1,160 @@ +Screen 0: minimum 8 x 8, current 1920 x 1200, maximum 32767 x 32767 +LVDS1 connected (normal left inverted right x axis y axis) + Identifier: 0x42 + Timestamp: 139526085 + Subpixel: horizontal rgb + Clones: + CRTCs: 1 0 + Transform: 1.000000 0.000000 0.000000 + 0.000000 1.000000 0.000000 + 0.000000 0.000000 1.000000 + filter: + EDID: + 00ffffffffffff0030e4e30200000000 + 00140103802213780aa9059f5e589c26 + 19505400000001010101010101010101 + 010101010101581b567e50000e302430 + 350058c2100000190000000000000000 + 00000000000000000000000000fe004c + 4720446973706c61790a2020000000fe + 004c503135365748342d544c42310071 + BACKLIGHT: 4882 + range: (0, 4882) + Backlight: 4882 + range: (0, 4882) + scaling mode: Full aspect + supported: None, Full, Center, Full aspect + 1366x768 (0x48) 70.000MHz -HSync -VSync +preferred + h: width 1366 start 1402 end 1450 total 1492 skew 0 clock 46.92KHz + v: height 768 start 771 end 776 total 782 clock 60.00Hz + 1360x768 (0xd4) 84.750MHz -HSync +VSync + h: width 1360 start 1432 end 1568 total 1776 skew 0 clock 47.72KHz + v: height 768 start 771 end 781 total 798 clock 59.80Hz + 1360x768 (0xd5) 72.000MHz +HSync -VSync + h: width 1360 start 1408 end 1440 total 1520 skew 0 clock 47.37KHz + v: height 768 start 771 end 781 total 790 clock 59.96Hz + 1280x720 (0xd6) 74.480MHz -HSync +VSync + h: width 1280 start 1336 end 1472 total 1664 skew 0 clock 44.76KHz + v: height 720 start 721 end 724 total 746 clock 60.00Hz + 1024x768 (0xd7) 65.000MHz -HSync -VSync + h: width 1024 start 1048 end 1184 total 1344 skew 0 clock 48.36KHz + v: height 768 start 771 end 777 total 806 clock 60.00Hz + 1024x576 (0xd8) 46.995MHz -HSync +VSync + h: width 1024 start 1064 end 1168 total 1312 skew 0 clock 35.82KHz + v: height 576 start 577 end 580 total 597 clock 60.00Hz + 960x540 (0xd9) 40.784MHz -HSync +VSync + h: width 960 start 992 end 1088 total 1216 skew 0 clock 33.54KHz + v: height 540 start 541 end 544 total 559 clock 60.00Hz + 800x600 (0xda) 40.000MHz +HSync +VSync + h: width 800 start 840 end 968 total 1056 skew 0 clock 37.88KHz + v: height 600 start 601 end 605 total 628 clock 60.32Hz + 800x600 (0xdb) 36.000MHz +HSync +VSync + h: width 800 start 824 end 896 total 1024 skew 0 clock 35.16KHz + v: height 600 start 601 end 603 total 625 clock 56.25Hz + 864x486 (0xdc) 32.901MHz -HSync +VSync + h: width 864 start 888 end 976 total 1088 skew 0 clock 30.24KHz + v: height 486 start 487 end 490 total 504 clock 60.00Hz + 640x480 (0xdd) 25.175MHz -HSync -VSync + h: width 640 start 656 end 752 total 800 skew 0 clock 31.47KHz + v: height 480 start 490 end 492 total 525 clock 59.94Hz + 720x405 (0xde) 22.176MHz -HSync +VSync + h: width 720 start 728 end 800 total 880 skew 0 clock 25.20KHz + v: height 405 start 406 end 409 total 420 clock 60.00Hz + 680x384 (0xdf) 19.677MHz -HSync +VSync + h: width 680 start 688 end 752 total 824 skew 0 clock 23.88KHz + v: height 384 start 385 end 388 total 398 clock 60.00Hz + 640x360 (0xe0) 17.187MHz -HSync +VSync + h: width 640 start 640 end 704 total 768 skew 0 clock 22.38KHz + v: height 360 start 361 end 364 total 373 clock 60.00Hz +DP1 disconnected (normal left inverted right x axis y axis) + Identifier: 0x43 + Timestamp: 139526085 + Subpixel: unknown + Clones: + CRTCs: 1 0 + Transform: 1.000000 0.000000 0.000000 + 0.000000 1.000000 0.000000 + 0.000000 0.000000 1.000000 + filter: + Broadcast RGB: Automatic + supported: Automatic, Full, Limited 16:235 + audio: auto + supported: force-dvi, off, auto, on +HDMI1 connected primary 1920x1200+0+0 (0x101) normal (normal left inverted right x axis y axis) 520mm x 320mm + Identifier: 0x44 + Timestamp: 139526085 + Subpixel: unknown + Gamma: 1.0:1.0:1.0 + Brightness: 1.0 + Clones: VGA1 + CRTC: 0 + CRTCs: 1 0 + Transform: 1.000000 0.000000 0.000000 + 0.000000 1.000000 0.000000 + 0.000000 0.000000 1.000000 + filter: + EDID: + 00ffffffffffff0010ac7aa04c374c32 + 1b16010380342078eaee95a3544c9926 + 0f5054a1080081408180a940b300d1c0 + 010101010101283c80a070b023403020 + 360006442100001a000000ff00593148 + 3554323734324c374c0a000000fc0044 + 454c4c2055323431324d0a20000000fd + 00323d1e5311000a2020202020200050 + aspect ratio: Automatic + supported: Automatic, 4:3, 16:9 + Broadcast RGB: Automatic + supported: Automatic, Full, Limited 16:235 + audio: auto + supported: force-dvi, off, auto, on + 1920x1200 (0x101) 154.000MHz +HSync -VSync *current +preferred + h: width 1920 start 1968 end 2000 total 2080 skew 0 clock 74.04KHz + v: height 1200 start 1203 end 1209 total 1235 clock 59.95Hz + 1920x1080 (0x102) 148.500MHz -HSync -VSync + h: width 1920 start 2008 end 2052 total 2200 skew 0 clock 67.50KHz + v: height 1080 start 1084 end 1089 total 1125 clock 60.00Hz + 1600x1200 (0x103) 162.000MHz +HSync +VSync + h: width 1600 start 1664 end 1856 total 2160 skew 0 clock 75.00KHz + v: height 1200 start 1201 end 1204 total 1250 clock 60.00Hz + 1680x1050 (0x104) 119.000MHz +HSync -VSync + h: width 1680 start 1728 end 1760 total 1840 skew 0 clock 64.67KHz + v: height 1050 start 1053 end 1059 total 1080 clock 59.88Hz + 1280x1024 (0x105) 108.000MHz +HSync +VSync + h: width 1280 start 1328 end 1440 total 1688 skew 0 clock 63.98KHz + v: height 1024 start 1025 end 1028 total 1066 clock 60.02Hz + 1280x960 (0x106) 108.000MHz +HSync +VSync + h: width 1280 start 1376 end 1488 total 1800 skew 0 clock 60.00KHz + v: height 960 start 961 end 964 total 1000 clock 60.00Hz + 1024x768 (0xd7) 65.000MHz -HSync -VSync + h: width 1024 start 1048 end 1184 total 1344 skew 0 clock 48.36KHz + v: height 768 start 771 end 777 total 806 clock 60.00Hz + 800x600 (0xda) 40.000MHz +HSync +VSync + h: width 800 start 840 end 968 total 1056 skew 0 clock 37.88KHz + v: height 600 start 601 end 605 total 628 clock 60.32Hz + 640x480 (0xdd) 25.175MHz -HSync -VSync + h: width 640 start 656 end 752 total 800 skew 0 clock 31.47KHz + v: height 480 start 490 end 492 total 525 clock 59.94Hz + 720x400 (0x107) 28.320MHz -HSync +VSync + h: width 720 start 738 end 846 total 900 skew 0 clock 31.47KHz + v: height 400 start 412 end 414 total 449 clock 70.08Hz +VGA1 disconnected (normal left inverted right x axis y axis) + Identifier: 0x45 + Timestamp: 139526085 + Subpixel: unknown + Clones: HDMI1 + CRTCs: 1 0 + Transform: 1.000000 0.000000 0.000000 + 0.000000 1.000000 0.000000 + 0.000000 0.000000 1.000000 + filter: +VIRTUAL1 disconnected (normal left inverted right x axis y axis) + Identifier: 0x46 + Timestamp: 139526085 + Subpixel: no subpixels + Clones: + CRTCs: 2 + Transform: 1.000000 0.000000 0.000000 + 0.000000 1.000000 0.000000 + 0.000000 0.000000 1.000000 + filter: -- 2.30.2