1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214

media / ffmpeg / scripts / credits_updater_unittest.py [blame]

#!/usr/bin/env python3
#
# Copyright 2015 The Chromium Authors.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import codecs
import copy
import credits_updater as cu
import os
import unittest

# Assumes this script is in ffmpeg/chromium/scripts/
SOURCE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                          os.path.pardir, os.path.pardir)
OUTPUT_FILE = 'CREDITS.testing'

# Expected credits for swresample.h applied with the rot13 encoding. Otherwise
# license scanners get confused about the license of this file.
SWRESAMPLE_H_LICENSE_ROT_13 = """yvofjerfnzcyr/fjerfnzcyr.u

Pbclevtug (P) 2011-2013 Zvpunry Avrqreznlre (zvpunryav@tzk.ng)

Guvf svyr vf cneg bs yvofjerfnzcyr

yvofjerfnzcyr vf serr fbsgjner; lbh pna erqvfgevohgr vg naq/be
zbqvsl vg haqre gur grezf bs gur TAH Yrffre Trareny Choyvp
Yvprafr nf choyvfurq ol gur Serr Fbsgjner Sbhaqngvba; rvgure
irefvba 2.1 bs gur Yvprafr, be (ng lbhe bcgvba) nal yngre irefvba.

yvofjerfnzcyr vf qvfgevohgrq va gur ubcr gung vg jvyy or hfrshy,
ohg JVGUBHG NAL JNEENAGL; jvgubhg rira gur vzcyvrq jneenagl bs
ZREPUNAGNOVYVGL be SVGARFF SBE N CNEGVPHYNE CHECBFR.  Frr gur TAH
Yrffre Trareny Choyvp Yvprafr sbe zber qrgnvyf.

Lbh fubhyq unir erprvirq n pbcl bs gur TAH Yrffre Trareny Choyvp
Yvprafr nybat jvgu yvofjerfnzcyr; vs abg, jevgr gb gur Serr Fbsgjner
Sbhaqngvba, Vap., 51 Senaxyva Fgerrg, Svsgu Sybbe, Obfgba, ZN 02110-1301 HFN"""

# The real expected credits for swresample.h.
SWRESAMPLE_H_LICENSE = codecs.decode(SWRESAMPLE_H_LICENSE_ROT_13, 'rot13')


def NewCreditsUpdater():
    return cu.CreditsUpdater(SOURCE_DIR, OUTPUT_FILE)


class CreditsUpdaterUnittest(unittest.TestCase):

    def tearDown(self):
        # Cleanup the testing output file
        test_credits = os.path.join(SOURCE_DIR, OUTPUT_FILE)
        if os.path.exists(test_credits):
            os.remove(test_credits)

    def testNoFiles(self):
        # Write credits without processing any files.
        NewCreditsUpdater().WriteCredits()

        # Credits should *always* have LICENSE.md followed by full LGPL text.
        expected_lines = NormalizeNewLines(GetLicenseMdLines() +
                                           GetSeparatorLines() +
                                           GetLicenseLines(cu.License.LGPL))
        credits_lines = ReadCreditsLines()
        self.assertEqual(expected_lines, credits_lines)

    def testLPGLFiles(self):
        # Process two known LGPL files
        updater = NewCreditsUpdater()
        updater.ProcessFile('libavformat/mp3dec.c')
        updater.ProcessFile('libavformat/mp3enc.c')
        updater.WriteCredits()

        # Expect output to have just LGPL text (once) preceded by LICENSE.md
        expected_lines = NormalizeNewLines(GetLicenseMdLines() +
                                           GetSeparatorLines() +
                                           GetLicenseLines(cu.License.LGPL))
        credits_lines = ReadCreditsLines()
        self.assertEqual(expected_lines, credits_lines)

    def testKnownBucketFiles(self):
        # Process some JPEG and MIPS files.
        updater = NewCreditsUpdater()
        updater.ProcessFile('libavcodec/jfdctfst.c')
        updater.ProcessFile('libavutil/mips/float_dsp_mips.c')
        updater.WriteCredits()

        # Expected output to have JPEG and MIPS text in addition to the typical LGPL
        # and LICENSE.md header. JPEG should appear before MIPS because known
        # buckets will be printed in alphabetical order.
        expected_lines = NormalizeNewLines(
            GetLicenseMdLines() + GetSeparatorLines() +
            ['libavcodec/jfdctfst.c\n\n'] + GetLicenseLines(cu.License.JPEG) +
            GetSeparatorLines() + ['libavutil/mips/float_dsp_mips.c\n\n'] +
            GetLicenseLines(cu.License.MIPS) + GetSeparatorLines() +
            GetLicenseLines(cu.License.LGPL))
        credits_lines = ReadCreditsLines()
        self.assertEqual(expected_lines, credits_lines)

    def testGeneratedAndKnownLicences(self):
        # Process a file that doesn't fall into a known bucket (e.g. the license
        # header for this file is unique). Also process a known bucket file.
        updater = NewCreditsUpdater()
        updater.ProcessFile('libswresample/swresample.h')
        updater.ProcessFile('libavutil/mips/float_dsp_mips.c')
        updater.WriteCredits()

        # Expect output to put swresample.h header first, followed by MIPS.
        expected_lines = NormalizeNewLines(
            GetLicenseMdLines() + GetSeparatorLines() +
            SWRESAMPLE_H_LICENSE.splitlines(True) + GetSeparatorLines() +
            ['libavutil/mips/float_dsp_mips.c\n\n'] +
            GetLicenseLines(cu.License.MIPS) + GetSeparatorLines() +
            GetLicenseLines(cu.License.LGPL))
        credits_lines = ReadCreditsLines()
        self.assertEqual(expected_lines, credits_lines)

    def testGeneratedLicencesOrder(self):
        # Process files that do not fall into a known bucket and assert that their
        # licenses are listed in alphabetical order of the file names.
        files = [
            'libswresample/swresample.h',
            'libavcodec/arm/jrevdct_arm.S',
            'libavcodec/mips/celp_math_mips.c',
            'libavcodec/mips/acelp_vectors_mips.c',
            'libavformat/oggparsetheora.c',
            'libavcodec/x86/xvididct.asm',
        ]
        updater = NewCreditsUpdater()
        for f in files:
            updater.ProcessFile(f)
        updater.WriteCredits()

        credits = ''.join(ReadCreditsLines())
        current_offset = 0
        for f in sorted(files):
            i = credits.find(f, current_offset)
            if i == -1:
                self.fail(
                    "Failed to find %s starting at offset %s of content:\n%s" %
                    (f, current_offset, credits))
            current_offset = i + len(f)

    def testKnownFileDigestChange(self):
        updater = NewCreditsUpdater()

        # Choose a known file.
        known_file = os.path.join('libavformat', 'oggparseogm.c')
        self.assertTrue(known_file in updater.known_file_map)

        # Show file processing works without raising SystemExit.
        updater.ProcessFile(known_file)

        # Alter the license digest for this file to simulate a change to the
        # license header.
        orig_file_info = updater.known_file_map[known_file]
        altered_file_info = cu.FileInfo(
            cu.License.LGPL, 'chris' + orig_file_info.license_digest[5:])
        updater.known_file_map[known_file] = altered_file_info

        # Verify digest mismatch triggers SystemExit.
        with self.assertRaises(SystemExit):
            updater.ProcessFile(known_file)


# Globals to cache the text of static files once read.
g_license_md_lines = []
g_license_lines = {}


def ReadCreditsLines():
    with open(os.path.join(SOURCE_DIR, OUTPUT_FILE)) as test_credits:
        return test_credits.readlines()


def GetLicenseMdLines():
    global g_license_md_lines
    if not len(g_license_md_lines):
        with open(os.path.join(SOURCE_DIR,
                               cu.UPSTREAM_LICENSEMD)) as license_md:
            g_license_md_lines = license_md.readlines()
    return g_license_md_lines


def GetLicenseLines(license_file):
    if not license_file in g_license_lines:
        g_license_lines[license_file] = GetFileLines(
            os.path.join(cu.LICENSE_TEXTS[license_file]))
    return g_license_lines[license_file]


def GetFileLines(file_path):
    with open(file_path) as open_file:
        return open_file.readlines()


def GetSeparatorLines():
    # Pass True to preserve \n chars in the return.
    return cu.LICENSE_SEPARATOR.splitlines(True)


# Combine into a string then split back out to a list. This is important for
# making constructed expectations match the credits read from a file. E.g.
# input: ['foo', '\n', 'bar']
# return: ['foo\n', 'bar']
# Comparing lists line by line makes for much better diffs when things go wrong.


def NormalizeNewLines(lines):
    return ''.join(lines).splitlines(True)


if __name__ == '__main__':
    unittest.main()