1# Software License Agreement (BSD License)
2#
3# Copyright (c) 2009, Willow Garage, Inc.
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9#
10#  * Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12#  * Redistributions in binary form must reproduce the above
13#    copyright notice, this list of conditions and the following
14#    disclaimer in the documentation and/or other materials provided
15#    with the distribution.
16#  * Neither the name of Willow Garage, Inc. nor the names of its
17#    contributors may be used to endorse or promote products derived
18#    from this software without specific prior written permission.
19#
20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31# POSSIBILITY OF SUCH DAMAGE.
32
33from __future__ import unicode_literals
34
35import os
36import sys
37from test.io_wrapper import StringIO
38import subprocess
39import re
40
41import wstool
42import wstool.helpers
43import wstool.wstool_cli
44from wstool.wstool_cli import WstoolCLI
45from wstool.wstool_cli import wstool_main
46
47import test.scm_test_base
48from test.scm_test_base import AbstractSCMTest, _add_to_file, _nth_line_split
49
50
51def create_svn_repo(test_root_path, remote_path, filler_path, svn_uri):
52    # create a "remote" repo
53    subprocess.check_call(["svnadmin", "create", remote_path], cwd=test_root_path)
54    subprocess.check_call(["svn", "checkout", svn_uri, filler_path], cwd=test_root_path)
55    subprocess.check_call(["touch", "fixed.txt"], cwd=filler_path)
56    subprocess.check_call(["touch", "modified.txt"], cwd=filler_path)
57    subprocess.check_call(["touch", "modified-fs.txt"], cwd=filler_path)
58    subprocess.check_call(["touch", "deleted.txt"], cwd=filler_path)
59    subprocess.check_call(["touch", "deleted-fs.txt"], cwd=filler_path)
60    subprocess.check_call(["svn", "add", "fixed.txt"], cwd=filler_path)
61    subprocess.check_call(["svn", "add", "modified.txt"], cwd=filler_path)
62    subprocess.check_call(["svn", "add", "modified-fs.txt"], cwd=filler_path)
63    subprocess.check_call(["svn", "add", "deleted.txt"], cwd=filler_path)
64    subprocess.check_call(["svn", "add", "deleted-fs.txt"], cwd=filler_path)
65    subprocess.check_call(["svn", "commit", "-m", "modified"], cwd=filler_path)
66
67
68def modify_svn_repo(clone_path):
69    # make local modifications
70    subprocess.check_call(["rm", "deleted-fs.txt"], cwd=clone_path)
71    subprocess.check_call(["svn", "rm", "deleted.txt"], cwd=clone_path)
72
73    #_add_to_file(os.path.join(clone_path, "modified-fs.txt"), "foo\n")
74    _add_to_file(os.path.join(clone_path, "modified.txt"), "foo\n")
75    _add_to_file(os.path.join(clone_path, "added-fs.txt"), "tada\n")
76    _add_to_file(os.path.join(clone_path, "added.txt"), "flam\n")
77    subprocess.check_call(["svn", "add", "--no-auto-props", "added.txt"], cwd=clone_path)
78
79
80class WstoolDiffSvnTest(AbstractSCMTest):
81
82    @classmethod
83    def setUpClass(self):
84        AbstractSCMTest.setUpClass()
85        remote_path = os.path.join(self.test_root_path, "remote")
86        filler_path = os.path.join(self.test_root_path, "filler")
87
88        svn_uri = "file://localhost" + remote_path
89
90        create_svn_repo(self.test_root_path, remote_path, filler_path, svn_uri)
91
92        # wstool the remote repo and fake ros
93        _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- svn: {local-name: clone, uri: '" + svn_uri + "'}")
94
95        cmd = ["wstool", "update", "-t", "ws"]
96        os.chdir(self.test_root_path)
97        wstool_main(cmd)
98        clone_path = os.path.join(self.local_path, "clone")
99
100        modify_svn_repo(clone_path)
101
102    def check_diff_output(self, output):
103        # svn 1.9 added the "nonexistent" output, replace it with the
104        # revision 0 that the test results expect.
105        output_fixed = re.sub("\(nonexistent\)", "(revision 0)", output)
106        # svn output order varies between versions
107        expected = ["""\
108Index: clone/added.txt
109===================================================================
110--- clone/added.txt\t(revision 0)
111+++ clone/added.txt\t""",
112"""@@ -0,0 +1 @@
113+flam""",
114                    """\
115Index: clone/modified.txt
116===================================================================
117--- clone/modified.txt\t(revision 1)
118+++ clone/modified.txt\t(working copy)
119@@ -0,0 +1 @@
120+foo"""]
121        for snippet in expected:
122            for line in snippet.splitlines():
123                # assertIn is not supported in Python2.6
124                self.assertTrue(line in output_fixed, output)
125
126    def test_wstool_diff_svn_outside(self):
127        """Test diff output for svn when run outside workspace"""
128
129        cmd = ["wstool", "diff", "-t", "ws"]
130        os.chdir(self.test_root_path)
131        sys.stdout = output = StringIO()
132        wstool_main(cmd)
133        sys.stdout = sys.__stdout__
134        output = output.getvalue()
135        self.check_diff_output(output)
136
137        cli = WstoolCLI()
138        self.assertEqual(0, cli.cmd_diff(os.path.join(self.test_root_path, 'ws'), []))
139
140    def test_wstool_diff_svn_inside(self):
141        """Test diff output for svn when run inside workspace"""
142        directory = self.test_root_path + "/ws"
143
144        cmd = ["wstool", "diff"]
145        os.chdir(directory)
146        sys.stdout = output = StringIO()
147        wstool_main(cmd)
148        output = output.getvalue()
149        sys.stdout = sys.__stdout__
150        self.check_diff_output(output)
151
152        cli = WstoolCLI()
153        self.assertEqual(0, cli.cmd_status(directory, []))
154
155    def test_wstool_status_svn_inside(self):
156        """Test status output for svn when run inside workspace"""
157        directory = self.test_root_path + "/ws"
158
159        cmd = ["wstool", "status"]
160        os.chdir(directory)
161        sys.stdout = output = StringIO()
162        wstool_main(cmd)
163        output = output.getvalue()
164        sys.stdout = sys.__stdout__
165
166        self.assertStatusListEqual('A       clone/added.txt\nD       clone/deleted.txt\n!       clone/deleted-fs.txt\nM       clone/modified.txt\n', output)
167
168        cli = WstoolCLI()
169        self.assertEqual(0, cli.cmd_diff(directory, []))
170
171    def test_wstool_status_svn_outside(self):
172        """Test status output for svn when run outside workspace"""
173
174        cmd = ["wstool", "status", "-t", "ws"]
175        os.chdir(self.test_root_path)
176        sys.stdout = output = StringIO()
177        wstool_main(cmd)
178        sys.stdout = sys.__stdout__
179        output = output.getvalue()
180        self.assertStatusListEqual('A       clone/added.txt\nD       clone/deleted.txt\n!       clone/deleted-fs.txt\nM       clone/modified.txt\n', output)
181
182        cli = WstoolCLI()
183        self.assertEqual(0, cli.cmd_status(os.path.join(self.test_root_path, 'ws'), []))
184
185    def test_wstool_status_svn_untracked(self):
186        """Test status output for svn when run outside workspace"""
187
188        cmd = ["wstool", "status", "-t", "ws", "--untracked"]
189        os.chdir(self.test_root_path)
190        sys.stdout = output = StringIO()
191        wstool_main(cmd)
192        sys.stdout = sys.__stdout__
193        output = output.getvalue()
194        self.assertStatusListEqual('?       clone/added-fs.txt\nA       clone/added.txt\nD       clone/deleted.txt\n!       clone/deleted-fs.txt\nM       clone/modified.txt\n', output)
195
196        cli = WstoolCLI()
197        self.assertEqual(0, cli.cmd_status(os.path.join(self.test_root_path, 'ws'), ["--untracked"]))
198
199    def test_wstool_info_svn(self):
200        cmd = ["wstool", "info", "-t", "ws"]
201        os.chdir(self.test_root_path)
202        sys.stdout = output = StringIO()
203        wstool_main(cmd)
204        output = output.getvalue()
205        tokens = _nth_line_split(-2, output)
206        self.assertEqual(['clone', 'M', 'svn'], tokens[0:3])
207
208        cli = WstoolCLI()
209        self.assertEqual(0, cli.cmd_info(os.path.join(self.test_root_path, 'ws'), []))
210
211
212class WstoolInfoSvnTest(AbstractSCMTest):
213
214    def setUp(self):
215        AbstractSCMTest.setUp(self)
216        remote_path = os.path.join(self.test_root_path, "remote")
217        filler_path = os.path.join(self.test_root_path, "filler")
218        self.svn_uri = "file://localhost" + remote_path
219
220        # create a "remote" repo
221        subprocess.check_call(["svnadmin", "create", remote_path], cwd=self.test_root_path)
222        subprocess.check_call(["svn", "checkout", self.svn_uri, filler_path], cwd=self.test_root_path)
223        subprocess.check_call(["touch", "test.txt"], cwd=filler_path)
224        subprocess.check_call(["svn", "add", "test.txt"], cwd=filler_path)
225        subprocess.check_call(["svn", "commit", "-m", "modified"], cwd=filler_path)
226        subprocess.check_call(["touch", "test2.txt"], cwd=filler_path)
227        subprocess.check_call(["svn", "add", "test2.txt"], cwd=filler_path)
228        subprocess.check_call(["svn", "commit", "-m", "modified"], cwd=filler_path)
229
230        self.version_init = "-r1"
231        self.version_end = "-r2"
232
233        # wstool the remote repo and fake ros
234        _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- svn: {local-name: clone, uri: '" + self.svn_uri + "'}")
235
236        cmd = ["wstool", "update"]
237        os.chdir(self.local_path)
238        sys.stdout = output = StringIO()
239        wstool_main(cmd)
240        output = output.getvalue()
241        sys.stdout = sys.__stdout__
242
243    def test_rosinstall_detailed_locapath_info(self):
244        cmd = ["wstool", "info", "-t", "ws"]
245        os.chdir(self.test_root_path)
246        sys.stdout = output = StringIO()
247        wstool_main(cmd)
248        output = output.getvalue()
249        tokens = _nth_line_split(-2, output)
250        self.assertEqual(['clone', 'svn', self.version_end, self.svn_uri], tokens)
251
252        clone_path = os.path.join(self.local_path, "clone")
253        # make local modifications check
254        subprocess.check_call(["touch", "test3.txt"], cwd=clone_path)
255        subprocess.check_call(["svn", "add", "test3.txt"], cwd=clone_path)
256        os.chdir(self.test_root_path)
257        sys.stdout = output = StringIO()
258        wstool_main(cmd)
259        output = output.getvalue()
260        tokens = _nth_line_split(-2, output)
261        self.assertEqual(['clone', 'M', 'svn', self.version_end, self.svn_uri], tokens)
262
263        subprocess.check_call(["rm", ".rosinstall"], cwd=self.local_path)
264        _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- svn: {local-name: clone, uri: '" + self.svn_uri + "', version: \"1\"}")
265        os.chdir(self.test_root_path)
266        sys.stdout = output = StringIO()
267        wstool_main(cmd)
268        output = output.getvalue()
269        tokens = _nth_line_split(-2, output)
270        self.assertEqual(['clone', 'MV', 'svn', '1', '(-)', self.version_end, "(%s)" % self.version_init, self.svn_uri], tokens)
271
272        subprocess.check_call(["rm", "-rf", "clone"], cwd=self.local_path)
273        os.chdir(self.test_root_path)
274        sys.stdout = output = StringIO()
275        wstool_main(cmd)
276        output = output.getvalue()
277        tokens = _nth_line_split(-2, output)
278        self.assertEqual(['clone', 'x', 'svn', '(-)', self.svn_uri], tokens)
279