2121from commands .preprocess import * #pylint: disable=unused-wildcard-import
2222import io
2323import os
24+ import sys
25+ import contextlib
2426import unittest
27+ import unittest .mock
2528from lxml import etree
2629
30+ class DummyFile (object ):
31+ def write (self , x ): pass
32+
33+ # From https://stackoverflow.com/a/2829036/1849769
34+ @contextlib .contextmanager
35+ def nostdout ():
36+ save_stdout = sys .stdout
37+ sys .stdout = DummyFile ()
38+ yield
39+ sys .stdout = save_stdout
40+
2741class TestConvertLoaderName (unittest .TestCase ):
2842 def test_convert_loader_name (self ):
2943 url = 'http://en.cppreference.com/mwiki/load.php?debug=false&lang=en&modules=site&only=scripts&skin=cppreference2&*'
@@ -225,7 +239,6 @@ def check_output(self, expected_file):
225239 actual = buf .getvalue ()
226240
227241 self .assertEqual (expected , actual )
228- pass
229242
230243 def test_remove_noprint (self ):
231244 remove_noprint (self .html )
@@ -250,3 +263,161 @@ def test_remove_fileinfo(self):
250263 def remove_unused_external (self ):
251264 remove_unused_external (self .html )
252265 self .check_output ("fabs_external.html" )
266+
267+ class TestFileRename (unittest .TestCase ):
268+ def make_rename_map (self , root ):
269+ def p (* dirs ):
270+ return os .path .join (root , 'dir1' , * dirs )
271+ return {
272+ 'invalid*.txt' : 'invalid_star_.txt' ,
273+ 'confl"ict".html' : 'confl_q_ict_q_.html' ,
274+ 'Confl"ict".html' : 'Confl_q_ict_q_.html' ,
275+ 'load.php?modules=site&only=scripts' : 'site_scripts.js' ,
276+ 'load.php?modules=someext&only=styles' : 'ext.css' ,
277+ p ('sub2' , 'Conflict.html' ): 'Conflict.2.html' ,
278+ p ('sub3' , 'Confl_q_ict_q_.html' ): 'Confl_q_ict_q_.2.html' ,
279+ p ('sub4' , 'Conflict' ): 'Conflict.2' ,
280+ p ('sub4' , 'conFlict' ): 'conFlict.3' ,
281+ p ('sub5' , 'Conflict' ): 'Conflict.2'
282+ }
283+
284+ def make_walk_result (self , root ):
285+ def p (* dirs ):
286+ return os .path .join (root , 'dir1' , * dirs )
287+ return [
288+ # Nothing to do
289+ (p (), ('sub1' , 'sub2' , 'sub3' , 'sub4' , 'sub5' , 'sub6' ), ('f1' , 'f2' )),
290+ # Unwanted characters
291+ (p ('sub1' ), (), ('invalid*.txt' , 'valid.txt' )),
292+ # Case conflict
293+ (p ('sub2' ), (), ('conflict.html' , 'Conflict.html' )),
294+ # Unwanted characters + case conflict
295+ (p ('sub3' ), (), ('confl"ict".html' , 'Confl"ict".html' )),
296+ # Multiple case conflicts, no extension
297+ (p ('sub4' ), (), ('conflict' , 'Conflict' , 'conFlict' )),
298+ # Case conflict in second directory
299+ (p ('sub5' ), (), ('conflict' , 'Conflict' )),
300+ # Loader links
301+ (p ('sub6' ), (), ('load.php?modules=site&only=scripts' , 'load.php?modules=someext&only=styles' ))
302+ ]
303+
304+ def test_build_rename_map (self ):
305+ with unittest .mock .patch ('os.walk' ) as walk :
306+ walk .return_value = self .make_walk_result ('output' )
307+
308+ actual = build_rename_map ('output' )
309+
310+ expected = self .make_rename_map ('output' )
311+ self .assertEqual (expected , actual )
312+
313+ def test_rename_files (self ):
314+ expected = [
315+ (('output/dir1/sub1/invalid*.txt' , 'output/dir1/sub1/invalid_star_.txt' ), {}),
316+ (('output/dir1/sub2/Conflict.html' , 'output/dir1/sub2/Conflict.2.html' ), {}),
317+ (('output/dir1/sub3/confl"ict".html' , 'output/dir1/sub3/confl_q_ict_q_.html' ), {}),
318+ (('output/dir1/sub3/Confl"ict".html' , 'output/dir1/sub3/Confl_q_ict_q_.2.html' ), {}),
319+ (('output/dir1/sub4/Conflict' , 'output/dir1/sub4/Conflict.2' ), {}),
320+ (('output/dir1/sub4/conFlict' , 'output/dir1/sub4/conFlict.3' ), {}),
321+ (('output/dir1/sub5/Conflict' , 'output/dir1/sub5/Conflict.2' ), {}),
322+ (('output/dir1/sub6/load.php?modules=site&only=scripts' , 'output/dir1/sub6/site_scripts.js' ), {}),
323+ (('output/dir1/sub6/load.php?modules=someext&only=styles' , 'output/dir1/sub6/ext.css' ), {})
324+ ]
325+
326+ actual = []
327+ def record_call (* args , ** kwargs ):
328+ actual .append ((args , kwargs ))
329+
330+ with unittest .mock .patch ('os.walk' ) as walk , \
331+ unittest .mock .patch ('shutil.move' ) as move :
332+ walk .return_value = self .make_walk_result ('output' )
333+ move .side_effect = record_call
334+
335+ with nostdout ():
336+ rename_files ('output' , self .make_rename_map ('output' ))
337+
338+ self .assertEqual (expected , actual ,
339+ msg = "Unexpected sequence of calls to shutil.move" )
340+
341+ def test_transform_relative_link (self ):
342+ entries = [
343+ # (file, target, expected)
344+ ('output/dir1/sub2/conflict.html' ,
345+ '../f1' ,
346+ '../f1' ),
347+
348+ ('output/dir1/sub2/Conflict.html' ,
349+ '../f1' ,
350+ '../f1' ),
351+
352+ ('output/dir1/sub2/Conflict.html' ,
353+ '../f1#p2' ,
354+ '../f1#p2' ),
355+
356+ ('output/dir1/sub2/Conflict.html' ,
357+ '../f1?some=param' ,
358+ '../f1' ),
359+
360+ ('output/dir1/sub2/Conflict.html' ,
361+ '../f1?some=param#p2' ,
362+ '../f1#p2' ),
363+
364+ ('output/dir1/sub2/Conflict.html' ,
365+ '../mwiki/site.css' ,
366+ '../common/site.css' ),
367+
368+ ('output/dir1/sub2/Conflict.html' ,
369+ '../../upload.cppreference.com/mwiki/site.css' ,
370+ '../common/site.css' ),
371+
372+ ('output/dir1/f2' ,
373+ 'sub1/invalid*.txt' ,
374+ 'sub1/invalid_star_.txt' ),
375+
376+ ('output/dir1/sub0/other.html' ,
377+ '../sub1/invalid*.txt' ,
378+ '../sub1/invalid_star_.txt' ),
379+
380+ ('output/dir1/sub1/valid.txt' ,
381+ '../sub2/conflict.html' ,
382+ '../sub2/conflict.html' ),
383+
384+ ('output/dir1/sub1/valid.txt' ,
385+ '../sub2/Conflict.html' ,
386+ '../sub2/Conflict.2.html' ),
387+
388+ ('output/dir1/sub1/valid.txt' ,
389+ '../sub3/confl"ict".html' ,
390+ '../sub3/confl_q_ict_q_.html' ),
391+
392+ ('output/dir1/sub1/valid.txt' ,
393+ '../sub3/Confl"ict".html' ,
394+ '../sub3/Confl_q_ict_q_.2.html' ),
395+
396+ ('output/dir1/sub1/valid.txt' ,
397+ '../sub4/conflict' ,
398+ '../sub4/conflict' ),
399+
400+ ('output/dir1/sub1/valid.txt' ,
401+ '../sub4/Conflict' ,
402+ '../sub4/Conflict.2' ),
403+
404+ ('output/dir1/sub1/valid.txt' ,
405+ '../sub4/conFlict' ,
406+ '../sub4/conFlict.3' ),
407+
408+ ('output/dir1/sub1/valid.txt' ,
409+ '../sub5/conflict' ,
410+ '../sub5/conflict' ),
411+
412+ ('output/dir1/sub1/valid.txt' ,
413+ '../sub5/Conflict' ,
414+ '../sub5/Conflict.2' ),
415+ ]
416+
417+ # trasform_relative_link(rename_map, target, file)
418+ # target: the relative link to transform, if target is in rename map
419+ # file: path of the file that contains the link
420+ rename_map = self .make_rename_map ('output' )
421+ for file , target , expected in entries :
422+ self .assertEqual (expected , trasform_relative_link (rename_map , target , file ),
423+ msg = "target='{}', file='{}'" .format (target , file ))
0 commit comments