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()