1#!/usr/bin/env python
2
3# This Source Code Form is subject to the terms of the Mozilla Public
4# License, v. 2.0. If a copy of the MPL was not distributed with this file,
5# You can obtain one at http://mozilla.org/MPL/2.0/.
6
7from __future__ import absolute_import
8
9import os
10import shutil
11import tempfile
12import unittest
13
14import mozunit
15
16from manifestparser import convert, ManifestParser
17
18
19class TestSymlinkConversion(unittest.TestCase):
20    """
21    test conversion of a directory tree with symlinks to a manifest structure
22    """
23
24    def create_stub(self, directory=None):
25        """stub out a directory with files in it"""
26
27        files = ("foo", "bar", "fleem")
28        if directory is None:
29            directory = tempfile.mkdtemp()
30        for i in files:
31            open(os.path.join(directory, i), "w").write(i)
32        subdir = os.path.join(directory, "subdir")
33        os.mkdir(subdir)
34        open(os.path.join(subdir, "subfile"), "w").write("baz")
35        return directory
36
37    def test_relpath(self):
38        """test convert `relative_to` functionality"""
39
40        oldcwd = os.getcwd()
41        stub = self.create_stub()
42        try:
43            # subdir with in-memory manifest
44            files = ["../bar", "../fleem", "../foo", "subfile"]
45            subdir = os.path.join(stub, "subdir")
46            os.chdir(subdir)
47            parser = convert([stub], relative_to=".")
48            self.assertEqual([i["name"] for i in parser.tests], files)
49        except BaseException:
50            raise
51        finally:
52            shutil.rmtree(stub)
53            os.chdir(oldcwd)
54
55    @unittest.skipIf(
56        not hasattr(os, "symlink"), "symlinks unavailable on this platform"
57    )
58    def test_relpath_symlink(self):
59        """
60        Ensure `relative_to` works in a symlink.
61        Not available on windows.
62        """
63
64        oldcwd = os.getcwd()
65        workspace = tempfile.mkdtemp()
66        try:
67            tmpdir = os.path.join(workspace, "directory")
68            os.makedirs(tmpdir)
69            linkdir = os.path.join(workspace, "link")
70            os.symlink(tmpdir, linkdir)
71            self.create_stub(tmpdir)
72
73            # subdir with in-memory manifest
74            files = ["../bar", "../fleem", "../foo", "subfile"]
75            subdir = os.path.join(linkdir, "subdir")
76            os.chdir(os.path.realpath(subdir))
77            for directory in (tmpdir, linkdir):
78                parser = convert([directory], relative_to=".")
79                self.assertEqual([i["name"] for i in parser.tests], files)
80        finally:
81            shutil.rmtree(workspace)
82            os.chdir(oldcwd)
83
84        # a more complicated example
85        oldcwd = os.getcwd()
86        workspace = tempfile.mkdtemp()
87        try:
88            tmpdir = os.path.join(workspace, "directory")
89            os.makedirs(tmpdir)
90            linkdir = os.path.join(workspace, "link")
91            os.symlink(tmpdir, linkdir)
92            self.create_stub(tmpdir)
93            files = ["../bar", "../fleem", "../foo", "subfile"]
94            subdir = os.path.join(linkdir, "subdir")
95            subsubdir = os.path.join(subdir, "sub")
96            os.makedirs(subsubdir)
97            linksubdir = os.path.join(linkdir, "linky")
98            linksubsubdir = os.path.join(subsubdir, "linky")
99            os.symlink(subdir, linksubdir)
100            os.symlink(subdir, linksubsubdir)
101            for dest in (subdir,):
102                os.chdir(dest)
103                for directory in (tmpdir, linkdir):
104                    parser = convert([directory], relative_to=".")
105                    self.assertEqual([i["name"] for i in parser.tests], files)
106        finally:
107            shutil.rmtree(workspace)
108            os.chdir(oldcwd)
109
110    @unittest.skipIf(
111        not hasattr(os, "symlink"), "symlinks unavailable on this platform"
112    )
113    def test_recursion_symlinks(self):
114        workspace = tempfile.mkdtemp()
115        self.addCleanup(shutil.rmtree, workspace)
116
117        # create two dirs
118        os.makedirs(os.path.join(workspace, "dir1"))
119        os.makedirs(os.path.join(workspace, "dir2"))
120
121        # create cyclical symlinks
122        os.symlink(os.path.join("..", "dir1"), os.path.join(workspace, "dir2", "ldir1"))
123        os.symlink(os.path.join("..", "dir2"), os.path.join(workspace, "dir1", "ldir2"))
124
125        # create one file in each dir
126        open(os.path.join(workspace, "dir1", "f1.txt"), "a").close()
127        open(os.path.join(workspace, "dir1", "ldir2", "f2.txt"), "a").close()
128
129        data = []
130
131        def callback(rootdirectory, directory, subdirs, files):
132            for f in files:
133                data.append(f)
134
135        ManifestParser._walk_directories([workspace], callback)
136        self.assertEqual(sorted(data), ["f1.txt", "f2.txt"])
137
138
139if __name__ == "__main__":
140    mozunit.main()
141