11from contextlib import contextmanager
2+ from datetime import datetime
23from itertools import product
34import os
45import shutil
4849 ('module_without_license.py' , '#' , 'module_with_license_nospace.py' , True , ['--no-space-in-comment-prefix' ]),
4950 ('module_without_license.php' , '/*| *| */' , 'module_with_license.php' , True , ['--insert-license-after-regex' , '^<\\ ?php$' ]),
5051 ('module_without_license.py' , '#' , 'module_with_license_noeol.py' , True , ['--no-extra-eol' ]),
52+
53+ ('module_without_license.groovy' , '//' , 'module_with_license.groovy' , True , ['--use-current-year' ]),
54+ ('module_with_stale_year_in_license.py' , '#' , 'module_with_year_range_in_license.py' , True , ['--use-current-year' ]),
55+ ('module_with_stale_year_range_in_license.py' , '#' , 'module_with_year_range_in_license.py' , True , ['--use-current-year' ]),
56+ ('module_with_badly_formatted_stale_year_range_in_license.py' , '#' , 'module_with_badly_formatted_stale_year_range_in_license.py' , False ,
57+ ['--use-current-year' ]),
5158 ),
5259 )),
5360)
@@ -69,6 +76,8 @@ def test_insert_license(license_file_path,
6976 if new_src_file_expected :
7077 with open (new_src_file_expected , encoding = encoding ) as expected_content_file :
7178 expected_content = expected_content_file .read ()
79+ if '--use-current-year' in args :
80+ expected_content = expected_content .replace ("2017" , str (datetime .now ().year ))
7281 new_file_content = path .open (encoding = encoding ).read ()
7382 assert new_file_content == expected_content
7483
@@ -127,23 +136,29 @@ def test_fuzzy_match_license(license_file_path,
127136
128137
129138@pytest .mark .parametrize (
130- ('src_file_content' , 'expected_index' ),
139+ ('src_file_content' , 'expected_index' , 'match_years_strictly' ),
131140 (
132- (['foo\n ' , 'bar\n ' ], None ),
133- (['# License line 1\n ' , '# License line 2\n ' , '\n ' , 'foo\n ' , 'bar\n ' ], 0 ),
134- (['\n ' , '# License line 1\n ' , '# License line 2\n ' , 'foo\n ' , 'bar\n ' ], 1 ),
141+ (['foo\n ' , 'bar\n ' ], None , True ),
142+ (['# License line 1\n ' , '# Copyright 2017\n ' , '\n ' , 'foo\n ' , 'bar\n ' ], 0 , True ),
143+ (['\n ' , '# License line 1\n ' , '# Copyright 2017\n ' , 'foo\n ' , 'bar\n ' ], 1 , True ),
144+ (['\n ' , '# License line 1\n ' , '# Copyright 2017\n ' , 'foo\n ' , 'bar\n ' ], 1 , False ),
145+ (['# License line 1\n ' , '# Copyright 1984\n ' , '\n ' , 'foo\n ' , 'bar\n ' ], None , True ),
146+ (['# License line 1\n ' , '# Copyright 1984\n ' , '\n ' , 'foo\n ' , 'bar\n ' ], 0 , False ),
147+ (['\n ' , '# License line 1\n ' , '# Copyright 2013,2015-2016\n ' , 'foo\n ' , 'bar\n ' ], 1 , False ),
135148 ),
136149)
137- def test_is_license_present (src_file_content , expected_index ):
150+ def test_is_license_present (src_file_content , expected_index , match_years_strictly ):
138151 license_info = LicenseInfo (
139152 plain_license = "" ,
140153 eol = "\n " ,
141154 comment_start = "" ,
142155 comment_prefix = "#" ,
143156 comment_end = "" ,
144157 num_extra_lines = 0 ,
145- prefixed_license = ['# License line 1\n ' , '# License line 2\n ' ])
146- assert expected_index == find_license_header_index (src_file_content , license_info , 5 )
158+ prefixed_license = ['# License line 1\n ' , '# Copyright 2017\n ' ])
159+ assert expected_index == find_license_header_index (
160+ src_file_content , license_info , 5 , match_years_strictly = match_years_strictly
161+ )
147162
148163
149164@pytest .mark .parametrize (
@@ -152,27 +167,35 @@ def test_is_license_present(src_file_content, expected_index):
152167 'comment_style' ,
153168 'fuzzy_match' ,
154169 'new_src_file_expected' ,
155- 'fail_check' ),
170+ 'fail_check' ,
171+ 'use_current_year' ),
156172 map (lambda a : a [:1 ] + a [1 ], product ( # combine license files with other args
157173 ('LICENSE_with_trailing_newline.txt' , 'LICENSE_without_trailing_newline.txt' ),
158174 (
159- ('module_with_license.css' , '/*| *| */' , False , 'module_without_license.css' , True ),
175+ ('module_with_license.css' , '/*| *| */' , False , 'module_without_license.css' , True , False ),
160176 ('module_with_license_and_few_words.css' , '/*| *| */' , False ,
161- 'module_without_license_and_few_words.css' , True ),
162- ('module_with_license_todo.css' , '/*| *| */' , False , None , True ),
163- ('module_with_fuzzy_matched_license.css' , '/*| *| */' , False , None , False ),
164- ('module_without_license.css' , '/*| *| */' , False , None , False ),
165-
166- ('module_with_license.py' , '#' , False , 'module_without_license.py' , True ),
167- ('module_with_license_and_shebang.py' , '#' , False , 'module_without_license_and_shebang.py' , True ),
168- ('init_with_license.py' , '#' , False , 'init_without_license.py' , True ),
169- ('init_with_license_and_newline.py' , '#' , False , 'init_without_license.py' , True ),
177+ 'module_without_license_and_few_words.css' , True , False ),
178+ ('module_with_license_todo.css' , '/*| *| */' , False , None , True , False ),
179+ ('module_with_fuzzy_matched_license.css' , '/*| *| */' , False , None , False , False ),
180+ ('module_without_license.css' , '/*| *| */' , False , None , False , False ),
181+
182+ ('module_with_license.py' , '#' , False , 'module_without_license.py' , True , False ),
183+ ('module_with_license_and_shebang.py' , '#' , False , 'module_without_license_and_shebang.py' , True , False ),
184+ ('init_with_license.py' , '#' , False , 'init_without_license.py' , True , False ),
185+ ('init_with_license_and_newline.py' , '#' , False , 'init_without_license.py' , True , False ),
170186 # Fuzzy match
171- ('module_with_license.css' , '/*| *| */' , True , 'module_without_license.css' , True ),
172- ('module_with_license_todo.css' , '/*| *| */' , True , None , True ),
173- ('module_with_fuzzy_matched_license.css' , '/*| *| */' , True , 'module_with_license_todo.css' , True ),
174- ('module_without_license.css' , '/*| *| */' , True , None , False ),
175- ('module_with_license_and_shebang.py' , '#' , True , 'module_without_license_and_shebang.py' , True ),
187+ ('module_with_license.css' , '/*| *| */' , True , 'module_without_license.css' , True , False ),
188+ ('module_with_license_todo.css' , '/*| *| */' , True , None , True , False ),
189+ ('module_with_fuzzy_matched_license.css' , '/*| *| */' , True , 'module_with_license_todo.css' , True , False ),
190+ ('module_without_license.css' , '/*| *| */' , True , None , False , False ),
191+ ('module_with_license_and_shebang.py' , '#' , True , 'module_without_license_and_shebang.py' , True , False ),
192+ # Strict and flexible years
193+ ('module_with_stale_year_in_license.py' , '#' , False , None , False , False ),
194+ ('module_with_stale_year_range_in_license.py' , '#' , False , None , False , False ),
195+ ('module_with_license.py' , '#' , False , 'module_without_license.py' , True , True ),
196+ ('module_with_stale_year_in_license.py' , '#' , False , 'module_without_license.py' , True , True ),
197+ ('module_with_stale_year_range_in_license.py' , '#' , False , 'module_without_license.py' , True , True ),
198+ ('module_with_badly_formatted_stale_year_range_in_license.py' , '#' , False , 'module_without_license.py' , True , True ),
176199 ),
177200 )),
178201)
@@ -182,6 +205,7 @@ def test_remove_license(license_file_path,
182205 fuzzy_match ,
183206 new_src_file_expected ,
184207 fail_check ,
208+ use_current_year ,
185209 tmpdir ):
186210 with chdir_to_test_resources ():
187211 path = tmpdir .join ('src_file_path' )
@@ -191,6 +215,8 @@ def test_remove_license(license_file_path,
191215 '--comment-style' , comment_style ]
192216 if fuzzy_match :
193217 argv = ['--fuzzy-match-generates-todo' ] + argv
218+ if use_current_year :
219+ argv = ['--use-current-year' ] + argv
194220 assert insert_license (argv ) == (1 if fail_check else 0 )
195221 if new_src_file_expected :
196222 with open (new_src_file_expected , encoding = 'utf-8' ) as expected_content_file :
0 commit comments