~ubuntu-branches/debian/experimental/dogtail/experimental

« back to all changes in this revision

Viewing changes to dogtail/tc.py

  • Committer: Package Import Robot
  • Author(s): Alessio Treglia
  • Date: 2013-02-09 16:01:44 UTC
  • mfrom: (1.2.2)
  • Revision ID: package-import@ubuntu.com-20130209160144-k2yk35tll4eew9wg
Tags: 0.8.1-1
* New maintainer. (Closes: #696136) (Closes: #553898)
* Set packaging format to 3.0 (quilt).
* New upstream release (Closes: #486452):
  - String exceptions are not used anymore. (Closes: #585287)
  - Fix missing check in findChildren(), tree.py (Closes: #485758)
* ACK NMUs:
  - Convert APT's API patch into the quilt format. (Closes: #572087)
  - Convert Ludovico Gardenghi's patch into the quilt
    format. (Closes: #485752)
* Fix desktop file as Freedesktop.org's per-spec.
* Migrate from CDBS + python-support to DH short-form + dh_python2.
* Move to section python.
* Refresh {,Build-}Depends lists.
* Remove xbase-clients from Depends. (Closes: #601486)
* Add Homepage field. (Closes: #572570)
* Add watch file.
* Add gbp config file.
* Refresh debian/copyright to meet copyright format 1.0.
* Install NEWS as upstream changelog.
* Bump Standards.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: <utf-8> -*-
 
1
# -*- coding: utf-8 -*-
2
2
"""Test Case magic
3
3
 
4
4
Author: Ed Rousseau <rousseau@redhat.com>"""
13
13
import os.path
14
14
from config import config
15
15
from logging import ResultsLogger, TimeStamp, debugLogger
16
 
from errors import DependencyNotFoundError
17
 
 
18
 
 
19
 
class TC:
 
16
from PIL import Image, ImageChops, ImageStat
 
17
 
 
18
 
 
19
class TC(object):
20
20
    """
21
21
    The Test Case Superclass
22
22
    """
81
81
    """
82
82
    Image Test Case Class.
83
83
    """
84
 
    IMVersion = ''
85
 
 
86
 
    def __init__(self):
87
 
        TC.__init__(self)
88
 
        self.supportedmetrics = ("MAE", "MSE", "PSE", "PSNR","RMSE", "none")
89
 
        self.scratchDir = config.scratchDir
90
 
        self.deldfile = 0
91
 
 
92
 
        # Get the ImageMagick version by parsing its '-version' output.
93
 
        IMVer = os.popen('compare -version').readline()
94
 
        IMVer = re.match('Version: ImageMagick ([0-9\.]+) .*', IMVer)
95
 
        if IMVer is not None:
96
 
            IMVer = IMVer.groups()[0]
97
 
            TCImage.IMVersion = IMVer
98
 
        else:
99
 
            raise DependencyNotFoundError, "ImageMagick"
100
 
 
101
 
    # Use ImageMagick to compare 2 files
102
 
    def compare(self, label, baseline, undertest, dfile='default', metric='none', threshold=0.0):
103
 
        """
104
 
        Calls ImageMagick's "compare" program. Default compares are based on
105
 
size but metric based comparisons are also supported with a threshold
106
 
determining pass/fail criteria.
107
 
        """
 
84
    def compare(self, label, baseline, undertest):
 
85
        for _file in (baseline, undertest):
 
86
            if type(_file) is not unicode and type(_file) is not str:
 
87
                raise TypeError("Need filenames!")
108
88
        self.label = label.strip()
109
89
        self.baseline = baseline.strip()
110
90
        self.undertest = undertest.strip()
111
 
        self.difference = 0.0
112
 
        self.metric = metric.strip()
113
 
        self.threshold = threshold
114
 
 
115
 
        # Create a default filename and flag it for deletion
116
 
        if dfile == "default":
117
 
            x = TimeStamp()
118
 
            # Remove all whitespace from the label since IM chokes on it
119
 
            splabel = label.split(" ")
120
 
            label = "".join(splabel)
121
 
            self.dfile = self.scratchDir + x.fileStamp(label)
122
 
            self.deldfile = 1
123
 
        else: # or use the supplied one with no deletion
124
 
            self.dfile = dfile
125
 
            self.deldfile = 0
126
 
 
127
 
        # Check to see if the metric type is supported
128
 
        if self.metric in self.supportedmetrics:
129
 
            # This is a bit convoluted and will be until IM completes
130
 
            # implementation of command line chaining. This should be put into
131
 
            # a try also munge together our IM call chain, if we're not doing
132
 
            # numeric metrics
133
 
            if self.metric == "none":
134
 
                # Build the comparison string. Redirect STDERR to STDOUT;
135
 
                # IM writes to STDERR and cmd reads STDOUT
136
 
                cmd = ("compare " + self.baseline + " " + self.undertest + " " + self.dfile + " " + "2>&1")
137
 
                # os.popen returns a list; if it is empty then we have passed
138
 
                answer = os.popen(cmd).readlines()
139
 
                if answer == []:
140
 
                    self.result = {self.label: "Passed - Images are the same size"}
141
 
                else:
142
 
                    fanswer = answer[0].strip()
143
 
                    self.result = {self.label: "Failed - " + fanswer}
144
 
                TC.logger.log(self.result)
145
 
                return self.result
146
 
            else: # otherwise run the metric code
147
 
                # Build the cmd
148
 
                cmd = ("compare -metric " + self.metric + " " + self.baseline + " " + self.undertest + " " + self.dfile + " " + "2>&1")
149
 
                answer = os.popen(cmd).readlines()
150
 
 
151
 
                # We need to check if the metric comparison failed. Unfortunately we
152
 
                # can only tell this by checking the length of the output of the
153
 
                # command. More unfortunately, ImageMagic changed the length of the
154
 
                # output at version 6.2.4, so we have to work around that.
155
 
                metricFailed = True
156
 
                IMVersion = TCImage.IMVersion
157
 
                if IMVersion <= '6.2.3' and len(answer) == 1: metricFailed = False
158
 
                if IMVersion >= '6.2.4' and len(answer) != 1: metricFailed = False
159
 
                if metricFailed:
160
 
                    fanswer = answer[0]
161
 
                    self.result = {self.label: "Failed - " + fanswer}
162
 
                else: # grab the metric from answer and convert it to a number
163
 
                    fanswer = answer[0].strip()
164
 
                    fanswer = fanswer.split(" ")
165
 
                    fanswer = fanswer[0]
166
 
                    fanswer = float(fanswer)
167
 
 
168
 
                    if fanswer == float("inf"): #same under PSNR returns inf dB:
169
 
                        self.result = {self.label: "Passed - " + "compare results: " + str(fanswer) + " dB"}
170
 
                    elif fanswer > self.threshold:
171
 
                        excess = fanswer - self.threshold
172
 
                        self.result = {self.label: "Failed - " + "compare result exceeds threshold by: " + str(excess) + " dB"}
173
 
                    else:
174
 
                        under = self.threshold - fanswer
175
 
                        self.result = {self.label: "Passed - " + "compare results under threshold by: " + str(under) + " dB"}
176
 
                TC.logger.log(self.result)
177
 
                return self.result
178
 
 
179
 
            # delete the composite image file if self.dfile is default
180
 
            if self.deldfile == 1:
181
 
                try:
182
 
                    os.remove(self.dfile)
183
 
                except IOError:
184
 
                    debugLogger.log("Could not delete tempfile " + self.dfile)
185
 
 
186
 
        else: # unsupported metric given
187
 
            self.result = {self.label: "Failed - " + self.metric + " is not in the list of supported metrics"}
188
 
            TC.logger.log(self.result)
189
 
            return self.result
190
 
 
 
91
        diffName = TimeStamp().fileStamp("diff") + ".png"
 
92
        self.diff = os.path.normpath(
 
93
                os.path.sep.join((config.scratchDir, diffName)))
 
94
 
 
95
        self.baseImage = Image.open(self.baseline)
 
96
        self.testImage = Image.open(self.undertest)
 
97
        try:
 
98
            if self.baseImage.size != self.testImage.size: 
 
99
                self.result = {self.label: "Failed - images are different sizes"}
 
100
                raise StopIteration
 
101
 
 
102
            self.diffImage = ImageChops.difference(self.baseImage, 
 
103
                    self.testImage)
 
104
            self.diffImage.save(self.diff)
 
105
            result = False
 
106
            for stat in ('stddev', 'mean', 'sum2'):
 
107
                for item in getattr(ImageStat.Stat(self.diffImage), stat):
 
108
                    if item: 
 
109
                        self.result = {self.label: "Failed - see %s" % 
 
110
                                self.diff}
 
111
                        raise StopIteration
 
112
                    else: result = True
 
113
        except StopIteration:
 
114
            result = False
 
115
 
 
116
        if result: self.result = {self.label: "Passed"}
 
117
 
 
118
        TC.logger.log(self.result)
 
119
        return self.result
191
120
 
192
121
 
193
122
class TCNumber(TC):
237
166
            TC.logger.log(self.result)
238
167
            return self.result
239
168
 
 
169
class TCBool(TC):
 
170
    def __init__(self): pass
 
171
 
 
172
    def compare(self, label, _bool):
 
173
        """
 
174
        If _bool is True, pass.
 
175
        If _bool is False, fail.
 
176
        """
 
177
        if type(_bool) is not bool: raise TypeError
 
178
        if _bool: result = {label: "Passed"}
 
179
        else: result = {label: "Failed"}
 
180
        TC.logger.log(result)
 
181
 
 
182
from tree import Node
 
183
class TCNode(TC):
 
184
    def __init__(self): pass
 
185
 
 
186
    def compare(self, label, baseline, undertest):
 
187
        """
 
188
        If baseline is None, simply check that undertest is a Node.
 
189
        If baseline is a Node, check that it is equal to undertest.
 
190
        """
 
191
        if baseline is not None and not isinstance(baseline, Node): 
 
192
            raise TypeError
 
193
 
 
194
        if not isinstance(undertest, Node):
 
195
            result = {label: "Failed - %s is not a Node" % undertest}
 
196
        elif baseline is None:
 
197
            result = {label: "Passed - %s is a Node" % undertest}
 
198
        elif isinstance(baseline, Node):
 
199
            if baseline == undertest: 
 
200
                result = {label: "Passed - %s == %s" % (baseline, undertest)}
 
201
            else: result = {label: "Failed - %s != %s" % (baseline, undertest)}
 
202
        TC.logger.log(result)
 
203
 
240
204
 
241
205
if __name__ == '__main__':
242
206
    # import the test modules
278
242
    label = " unit test case 2.0"
279
243
    encoding = "utf-8"
280
244
    baseline = u"groß"
281
 
    undertest = u"gro\xc3\xa1"
 
245
    undertest = u"gro\xdf"
282
246
    result = {}
283
247
 
284
248
    # Fire off a UTF-8 compare
379
343
    # Print the entrystamp - should be YYYY-MM-DD_HH:MM:SS with local system time
380
344
    print entry
381
345
 
382
 
    # Test to see that image compares work - this a simple compare with defaults
383
 
    # Load our variabes
 
346
    # Copmare different colors
384
347
    label = "unit test case 3.0"
385
348
    baseline = "../examples/data/20w.png"
386
349
    undertest = "../examples/data/20b.png"
392
355
    # Fire off the compare
393
356
    result = case3.compare(label, baseline, undertest)
394
357
 
395
 
    # Print the result Should be label - Passed - Images are same size
 
358
    # Print the result Should be label - Failed
396
359
    print result
397
360
 
398
 
    # Default compare with different images (the sizes differ)
 
361
    # Compare different sizes
399
362
    label = "unit test case 3.1"
400
363
    baseline = "../examples/data/20w.png"
401
364
    undertest = "../examples/data/10w.png"
404
367
    # Fire off the compare
405
368
    result = case3.compare(label, baseline, undertest)
406
369
 
407
 
    # Print the result Should be label - Failied compare:Images differ in size
 
370
    # Print the result Should be label - Failed
408
371
    print result
409
372
 
410
 
    # Image compare pass with the metrics option
 
373
    # Compare the same image
411
374
    label = "unit test case 3.2"
412
 
    baseline = "../examples/data/20w.png"
413
 
    undertest = "../examples/data/20b.png"
414
 
    result = {}
415
 
    metrics = ("MAE", "MSE", "PSE", "PSNR"," RMSE")
416
 
 
417
 
    for i in range(len(metrics)):
418
 
        result = case3.compare(label, baseline, undertest, metric=metrics[i])
419
 
        print metrics[i]
420
 
        print result
421
 
 
422
 
    # Image compare fail metrics
423
 
    label = "unit test case 3.3"
424
 
    baseline = "../examples/data/10w.png"
425
 
    undertest = "../examples/data/10b.png"
426
 
    result = {}
427
 
    metrics = ("MAE", "MSE", "PSE", "PSNR"," RMSE")
428
 
 
429
 
    for i in range(len(metrics)):
430
 
        result = case3.compare(label, baseline, undertest, metric=metrics[i])
431
 
        print metrics[i]
432
 
        print result
433
 
 
434
 
    # Image comapre threshold metrics - only PNSR should pass
435
 
    label = "unit test case 3.4"
436
 
    baseline = "../examples/data/10w.png"
437
 
    undertest = "../examples/data/10b.png"
438
 
    result = {}
439
 
    metrics = ("MAE", "MSE", "PSE", "PSNR"," RMSE")
440
 
    bound = 5
441
 
 
442
 
    for i in range(len(metrics)):
443
 
        result = case3.compare(label, baseline, undertest, metric=metrics[i], threshold=bound)
444
 
        print metrics[i]
445
 
        print result
446
 
 
447
 
    # Bogus metric test
448
 
    label = "unit test case 3.5"
449
 
    baseline = "../examples/data/10w.png"
450
 
    undertest = "../examples/data/10b.png"
451
 
    result = {}
452
 
    metrics = "Guess"
453
 
 
454
 
    result = case3.compare(label, baseline, undertest, metric=metrics)
455
 
 
456
 
    # Should be failed - metric unsupported
 
375
    baseline = "../examples/data/10w.png"
 
376
    undertest = "../examples/data/10w.png"
 
377
    result = {}
 
378
 
 
379
    # Fire off the compare
 
380
    result = case3.compare(label, baseline, undertest)
 
381
 
 
382
    # Print the result Should be label - Passed
457
383
    print result
458
384
 
459
385
    # Number comparison tests