1#!/pxrpythonsubst
2#
3# Copyright 2019 Pixar
4#
5# Licensed under the Apache License, Version 2.0 (the "Apache License")
6# with the following modification; you may not use this file except in
7# compliance with the Apache License and the following modification to it:
8# Section 6. Trademarks. is deleted and replaced with:
9#
10# 6. Trademarks. This License does not grant permission to use the trade
11#    names, trademarks, service marks, or product names of the Licensor
12#    and its affiliates, except as required to comply with Section 4(c) of
13#    the License and to reproduce the content of the NOTICE file.
14#
15# You may obtain a copy of the Apache License at
16#
17#     http://www.apache.org/licenses/LICENSE-2.0
18#
19# Unless required by applicable law or agreed to in writing, software
20# distributed under the Apache License with the above modification is
21# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
22# KIND, either express or implied. See the Apache License for the specific
23# language governing permissions and limitations under the Apache License.
24
25from pxr import Sdf
26from pxr import Usd
27from pxr import UsdAppUtils
28from pxr import UsdUtils
29
30import argparse
31import os
32import sys
33import unittest
34
35
36class _NonExitingArgumentParser(argparse.ArgumentParser):
37    def error(self, message):
38        # We override just this method so that we can avoid exiting and detect
39        # error conditions.
40        raise ValueError(message)
41
42class TestUsdAppUtilsCmdlineArgs(unittest.TestCase):
43
44    @classmethod
45    def setUpClass(cls):
46        cls._progName = os.path.basename(sys.argv[0])
47
48    def setUp(self):
49        self._parser = argparse.ArgumentParser(prog=self._progName)
50
51    def testCameraCmdlineArgs(self):
52        """
53        Tests argument parsing when camera-related args are added.
54        """
55        UsdAppUtils.cameraArgs.AddCmdlineArgs(self._parser)
56
57        # By default, the camera arg should contain the primary camera name.
58        args = self._parser.parse_args([])
59        self.assertEqual(type(args.camera), Sdf.Path)
60        self.assertEqual(args.camera.pathString,
61            UsdUtils.GetPrimaryCameraName())
62
63        args = self._parser.parse_args(['--camera', 'MainCamera'])
64        self.assertEqual(type(args.camera), Sdf.Path)
65        self.assertEqual(args.camera.pathString, 'MainCamera')
66
67        args = self._parser.parse_args(['-cam', 'MainCamera'])
68        self.assertEqual(type(args.camera), Sdf.Path)
69        self.assertEqual(args.camera.pathString, 'MainCamera')
70
71        args = self._parser.parse_args(['--camera', '/Path/To/Some/Camera'])
72        self.assertEqual(type(args.camera), Sdf.Path)
73        self.assertEqual(args.camera.pathString, '/Path/To/Some/Camera')
74
75        args = self._parser.parse_args(['--camera', ''])
76        self.assertEqual(type(args.camera), Sdf.Path)
77        self.assertEqual(args.camera, Sdf.Path.emptyPath)
78
79        # Test adding camera args with a different default value.
80        parser = argparse.ArgumentParser(prog=self._progName)
81        UsdAppUtils.cameraArgs.AddCmdlineArgs(parser,
82            defaultValue='MainCamera')
83        args = parser.parse_args([])
84        self.assertEqual(type(args.camera), Sdf.Path)
85        self.assertEqual(args.camera.pathString, 'MainCamera')
86
87    def testColorCmdlineArgs(self):
88        """
89        Tests argument parsing when color-related args are added.
90        """
91        UsdAppUtils.colorArgs.AddCmdlineArgs(self._parser)
92
93        args = self._parser.parse_args([])
94        self.assertEqual(args.colorCorrectionMode, 'sRGB')
95
96        args = self._parser.parse_args(['--colorCorrectionMode', 'disabled'])
97        self.assertEqual(args.colorCorrectionMode, 'disabled')
98
99        args = self._parser.parse_args(['-color', 'openColorIO'])
100        self.assertEqual(args.colorCorrectionMode, 'openColorIO')
101
102        # Test adding color args with a different default value.
103        parser = argparse.ArgumentParser(prog=self._progName)
104        UsdAppUtils.colorArgs.AddCmdlineArgs(parser, defaultValue='disabled')
105        args = parser.parse_args([])
106        self.assertEqual(args.colorCorrectionMode, 'disabled')
107
108        # Test passing an invalid option.
109        parser = _NonExitingArgumentParser(prog=self._progName)
110        UsdAppUtils.colorArgs.AddCmdlineArgs(parser)
111        with self.assertRaises(ValueError):
112            args = parser.parse_args(['--colorCorrectionMode', 'bogus'])
113
114    def testComplexityCmdlineArgs(self):
115        """
116        Tests argument parsing when complexity-related args are added.
117        """
118        UsdAppUtils.complexityArgs.AddCmdlineArgs(self._parser)
119
120        args = self._parser.parse_args([])
121        self.assertEqual(args.complexity,
122            UsdAppUtils.complexityArgs.RefinementComplexities.LOW)
123
124        args = self._parser.parse_args(['--complexity', 'medium'])
125        self.assertEqual(args.complexity,
126            UsdAppUtils.complexityArgs.RefinementComplexities.MEDIUM)
127
128        args = self._parser.parse_args(['-c', 'high'])
129        self.assertEqual(args.complexity,
130            UsdAppUtils.complexityArgs.RefinementComplexities.HIGH)
131
132        # Test adding complexity args with a different default value.
133        parser = argparse.ArgumentParser(prog=self._progName)
134        UsdAppUtils.complexityArgs.AddCmdlineArgs(parser,
135            defaultValue='veryhigh')
136        args = parser.parse_args([])
137        self.assertEqual(args.complexity,
138            UsdAppUtils.complexityArgs.RefinementComplexities.VERY_HIGH)
139
140        # Test passing an invalid option.
141        parser = _NonExitingArgumentParser(prog=self._progName)
142        UsdAppUtils.complexityArgs.AddCmdlineArgs(parser)
143        with self.assertRaises(ValueError):
144            args = parser.parse_args(['--complexity', 'bogus'])
145
146    def testFramesCmdlineArgs(self):
147        """
148        Tests argument parsing when frame-related args are added.
149        """
150        UsdAppUtils.framesArgs.AddCmdlineArgs(self._parser)
151
152        args = self._parser.parse_args([])
153        UsdAppUtils.framesArgs.ValidateCmdlineArgs(self._parser, args)
154        self.assertEqual(args.frames, [Usd.TimeCode.EarliestTime()])
155
156        args = self._parser.parse_args(['--defaultTime'])
157        UsdAppUtils.framesArgs.ValidateCmdlineArgs(self._parser, args)
158        self.assertEqual(args.frames, [Usd.TimeCode.Default()])
159
160        args = self._parser.parse_args(['--d'])
161        UsdAppUtils.framesArgs.ValidateCmdlineArgs(self._parser, args)
162        self.assertEqual(args.frames, [Usd.TimeCode.Default()])
163
164        args = self._parser.parse_args(['--frames', '1:4'])
165        UsdAppUtils.framesArgs.ValidateCmdlineArgs(self._parser, args)
166        self.assertEqual(type(args.frames),
167            UsdAppUtils.framesArgs.FrameSpecIterator)
168        self.assertEqual(list(args.frames),
169            [Usd.TimeCode(1.0),
170             Usd.TimeCode(2.0),
171             Usd.TimeCode(3.0),
172             Usd.TimeCode(4.0)])
173
174        args = self._parser.parse_args(['-f', '11,13:15x2,17'])
175        UsdAppUtils.framesArgs.ValidateCmdlineArgs(self._parser, args)
176        self.assertEqual(type(args.frames),
177            UsdAppUtils.framesArgs.FrameSpecIterator)
178        self.assertEqual(list(args.frames),
179            [Usd.TimeCode(11.0),
180             Usd.TimeCode(13.0),
181             Usd.TimeCode(15.0),
182             Usd.TimeCode(17.0)])
183
184        # Test that a frame format arg is correctly converted for use with
185        # string.format().
186        parser = argparse.ArgumentParser(prog=self._progName)
187        UsdAppUtils.framesArgs.AddCmdlineArgs(parser)
188        parser.add_argument('outputImagePath', action='store', type=str,
189            help='output image path')
190        args = parser.parse_args(['test_image.#.png', '--frames', '1:4'])
191        UsdAppUtils.framesArgs.ValidateCmdlineArgs(parser, args,
192            frameFormatArgName='outputImagePath')
193        self.assertEqual(args.outputImagePath, 'test_image.{frame:01.0f}.png')
194
195        args = parser.parse_args(['test_image.###.#.png', '--frames', '1:4'])
196        UsdAppUtils.framesArgs.ValidateCmdlineArgs(parser, args,
197            frameFormatArgName='outputImagePath')
198        self.assertEqual(args.outputImagePath, 'test_image.{frame:05.1f}.png')
199
200        # Test that an error is raised if the frame format arg does not contain
201        # a frame placeholder when frames are given.
202        parser = _NonExitingArgumentParser(prog=self._progName)
203        UsdAppUtils.framesArgs.AddCmdlineArgs(parser)
204        parser.add_argument('outputImagePath', action='store', type=str,
205            help='output image path')
206        args = parser.parse_args(['test_image.png', '--frames', '1:4'])
207        with self.assertRaises(ValueError):
208            UsdAppUtils.framesArgs.ValidateCmdlineArgs(parser, args,
209                frameFormatArgName='outputImagePath')
210
211        # Test that an error is raised if the frame format arg does contain
212        # a frame placeholder but no frames are given.
213        parser = _NonExitingArgumentParser(prog=self._progName)
214        UsdAppUtils.framesArgs.AddCmdlineArgs(parser)
215        parser.add_argument('outputImagePath', action='store', type=str,
216            help='output image path')
217        args = parser.parse_args(['test_image.#.png'])
218        with self.assertRaises(ValueError):
219            UsdAppUtils.framesArgs.ValidateCmdlineArgs(parser, args,
220                frameFormatArgName='outputImagePath')
221
222        args = parser.parse_args(['test_image.#.png', '--defaultTime'])
223        with self.assertRaises(ValueError):
224            UsdAppUtils.framesArgs.ValidateCmdlineArgs(parser, args,
225                frameFormatArgName='outputImagePath')
226
227        # Tests that an error is raised if the floating point precision
228        # specified in the frame format arg is less than the minimum floating
229        # point precision required for the given FrameSpecs.
230        parser = _NonExitingArgumentParser(prog=self._progName)
231        UsdAppUtils.framesArgs.AddCmdlineArgs(parser)
232        parser.add_argument('outputImagePath', action='store', type=str,
233            help='output image path')
234        args = parser.parse_args(['test_image.#.png', '--frames', '1:4x0.1'])
235        with self.assertRaises(ValueError):
236            UsdAppUtils.framesArgs.ValidateCmdlineArgs(parser, args,
237                frameFormatArgName='outputImagePath')
238        args = parser.parse_args(['test_image.#.##.png', '--frames',
239            '101:105x0.1,106:109x0.125,110:114x0.25'])
240        with self.assertRaises(ValueError):
241            UsdAppUtils.framesArgs.ValidateCmdlineArgs(parser, args,
242                frameFormatArgName='outputImagePath')
243
244    def testRendererCmdlineArgs(self):
245        """
246        Tests argument parsing when Hydra renderer-related args are added.
247        """
248        UsdAppUtils.rendererArgs.AddCmdlineArgs(self._parser)
249
250        # No renderer plugin is specified by default.
251        args = self._parser.parse_args([])
252        self.assertEqual(args.rendererPlugin, None)
253
254        args = self._parser.parse_args(['--renderer', 'GL'])
255        self.assertEqual(args.rendererPlugin, 'GL')
256
257        args = self._parser.parse_args(['-r', 'GL'])
258        self.assertEqual(args.rendererPlugin, 'GL')
259
260        # Test passing an invalid option.
261        parser = _NonExitingArgumentParser(prog=self._progName)
262        UsdAppUtils.rendererArgs.AddCmdlineArgs(parser)
263        with self.assertRaises(ValueError):
264            args = parser.parse_args(['--renderer', 'bogus'])
265
266
267if __name__ == "__main__":
268    unittest.main()
269