text: import unittest
  
  from robot.variables import Variables
  from robot.errors import DataError, VariableError
  from robot.utils.asserts import assert_equal, assert_raises
  
  
  SCALARS = ['${var}', '${  v A  R }']
  LISTS = ['@{var}', '@{  v A  R }']
  NOKS = ['var', '$var', '${var', '${va}r', '@{va}r', '@var', '%{var}', ' ${var}',
          '@{var} ', '\\${var}', '\\\\${var}', 42, None, ['${var}'], DataError]
  
  
  class PythonObject:
      def __init__(self, a, b):
          self.a = a
          self.b = b
      def __getitem__(self, index):
          return (self.a, self.b)[index]
      def __str__(self):
          return '(%s, %s)' % (self.a, self.b)
      def __len__(self):
          return 2
      __repr__ = __str__
  
  
  class TestVariables(unittest.TestCase):
  
      def setUp(self):
          self.varz = Variables()
  
      def test_set(self):
          value = ['value']
          for var in SCALARS + LISTS:
              self.varz[var] = value
              assert_equal(self.varz[var], value)
              assert_equal(self.varz[var.lower().replace(' ', '')], value)
              self.varz.clear()
  
      def test_set_invalid(self):
          for var in NOKS:
              assert_raises(DataError, self.varz.__setitem__, var, 'value')
  
      def test_set_scalar(self):
          for var in SCALARS:
              for value in ['string', '', 10, ['hi', 'u'], ['hi', 2],
                            {'a': 1, 'b': 2}, self, None, unittest.TestCase]:
                  self.varz[var] = value
                  assert_equal(self.varz[var], value)
  
      def test_set_list(self):
          for var in LISTS:
              for value in [[], [''], ['str'], [10], ['hi', 'u'], ['hi', 2],
                            [{'a': 1, 'b': 2}, self, None]]:
                  self.varz[var] = value
                  assert_equal(self.varz[var], value)
                  self.varz.clear()
  
      def test_replace_scalar(self):
          self.varz['${foo}'] = 'bar'
          self.varz['${a}'] = 'ari'
          for inp, exp in [('${foo}', 'bar'),
                           ('${a}', 'ari'),
                           (r'$\{a}', '${a}'),
                           ('', ''),
                           ('hii', 'hii'),
                           ("Let's go to ${foo}!", "Let's go to bar!"),
                           ('${foo}ba${a}-${a}', 'barbaari-ari')]:
              assert_equal(self.varz.replace_scalar(inp), exp)
  
      def test_replace_list(self):
          self.varz['@{L}'] = ['v1', 'v2']
          self.varz['@{E}'] = []
          self.varz['@{S}'] = ['1', '2', '3']
          for inp, exp in [(['@{L}'], ['v1', 'v2']),
                           (['@{L}', 'v3'], ['v1', 'v2', 'v3']),
                           (['v0', '@{L}', '@{E}', 'v${S}[2]'], ['v0', 'v1', 'v2', 'v3']),
                           ([], []),
                           (['hi u', 'hi 2', 3], ['hi u','hi 2', 3])]:
              assert_equal(self.varz.replace_list(inp), exp)
  
      def test_replace_list_in_scalar_context(self):
          self.varz['@{list}'] = ['v1', 'v2']
          assert_equal(self.varz.replace_list(['@{list}']), ['v1', 'v2'])
          assert_equal(self.varz.replace_list(['-@{list}-']), ["-['v1', 'v2']-"])
  
      def test_replace_list_item(self):
          self.varz['@{L}'] = ['v0', 'v1']
          assert_equal(self.varz.replace_list(['${L}[0]']), ['v0'])
          assert_equal(self.varz.replace_scalar('${L}[1]'), 'v1')
          assert_equal(self.varz.replace_scalar('-${L}[0]${L}[1]${L}[0]-'), '-v0v1v0-')
          self.varz['${L2}'] = ['v0', ['v11', 'v12']]
          assert_equal(self.varz.replace_list(['${L2}[0]']), ['v0'])
          assert_equal(self.varz.replace_list(['${L2}[1]']), [['v11', 'v12']])
          assert_equal(self.varz.replace_scalar('${L2}[0]'), 'v0')
          assert_equal(self.varz.replace_scalar('${L2}[1]'), ['v11', 'v12'])
          assert_equal(self.varz.replace_list(['${L}[0]', '@{L2}[1]']), ['v0', 'v11', 'v12'])
  
      def test_replace_dict_item(self):
          self.varz['&{D}'] = {'a': 1, 2: 'b', 'nested': {'a': 1}}
          assert_equal(self.varz.replace_scalar('${D}[a]'), 1)
          assert_equal(self.varz.replace_scalar('${D}[${2}]'), 'b')
          assert_equal(self.varz.replace_scalar('${D}[nested][a]'), 1)
          assert_equal(self.varz.replace_scalar('${D}[nested]'), {'a': 1})
          assert_equal(self.varz.replace_scalar('&{D}[nested]'), {'a': 1})
  
      def test_replace_non_strings(self):
          self.varz['${d}'] = {'a': 1, 'b': 2}
          self.varz['${n}'] = None
          assert_equal(self.varz.replace_scalar('${d}'), {'a': 1, 'b': 2})
          assert_equal(self.varz.replace_scalar('${n}'), None)
  
      def test_replace_non_strings_inside_string(self):
          class Example:
              def __str__(self):
                  return 'Hello'
          self.varz['${h}'] = Example()
          self.varz['${w}'] = 'world'
          res = self.varz.replace_scalar('Another "${h} ${w}" example')
          assert_equal(res, 'Another "Hello world" example')
  
      def test_replace_list_item_invalid(self):
          self.varz['@{L}'] = ['v0', 'v1', 'v3']
          for inv in ['@{L}[3]', '@{NON}[0]', '@{L[2]}']:
              assert_raises(VariableError, self.varz.replace_list, [inv])
  
      def test_replace_non_existing_list(self):
          assert_raises(VariableError, self.varz.replace_list, ['${nonexisting}'])
  
      def test_replace_non_existing_scalar(self):
          assert_raises(VariableError, self.varz.replace_scalar, '${nonexisting}')
  
      def test_replace_non_existing_string(self):
          assert_raises(VariableError, self.varz.replace_string, '${nonexisting}')
  
      def test_non_string_input(self):
          for item in [1, False, None, [], (), {}, object]:
              assert_equal(self.varz.replace_list([item]), [item])
              assert_equal(self.varz.replace_scalar(item), item)
              assert_equal(self.varz.replace_string(item), str(item))
  
      def test_replace_escaped(self):
          self.varz['${foo}'] = 'bar'
          for inp, exp in [(r'\${foo}', r'${foo}'),
                           (r'\\${foo}', r'\bar'),
                           (r'\\\${foo}', r'\${foo}'),
                           (r'\\\\${foo}', r'\\bar'),
                           (r'\\\\\${foo}', r'\\${foo}')]:
              assert_equal(self.varz.replace_scalar(inp), exp)
  
      def test_variables_in_value(self):
          self.varz['${exists}'] = 'Variable exists but is still not replaced'
          self.varz['${test}'] = '${exists} & ${does_not_exist}'
          assert_equal(self.varz['${test}'], '${exists} & ${does_not_exist}')
          self.varz['@{test}'] = ['${exists}', '&', '${does_not_exist}']
          assert_equal(self.varz['@{test}'], '${exists} & ${does_not_exist}'.split())
  
      def test_variable_as_object(self):
          obj = PythonObject('a', 1)
          self.varz['${obj}'] = obj
          assert_equal(self.varz['${obj}'], obj)
          expected = ['Some text here %s and %s there' % (obj, obj)]
          actual = self.varz.replace_list(['Some text here ${obj} and ${obj} there'])
          assert_equal(actual, expected)
  
      def test_extended_variables(self):
          # Extended variables are vars like ${obj.name} when we have var ${obj}
          obj = PythonObject('a', [1, 2, 3])
          dic = {'a': 1, 'o': obj}
          self.varz['${obj}'] = obj
          self.varz['${dic}'] = dic
          assert_equal(self.varz.replace_scalar('${obj.a}'), 'a')
          assert_equal(self.varz.replace_scalar('${obj.b}'), [1, 2, 3])
          assert_equal(self.varz.replace_scalar('${obj.b[0]}-${obj.b[1]}'), '1-2')
          assert_equal(self.varz.replace_scalar('${dic["a"]}'), 1)
          assert_equal(self.varz.replace_scalar('${dic["o"]}'), obj)
          assert_equal(self.varz.replace_scalar('-${dic["o"].b[2]}-'), '-3-')
  
      def test_space_is_not_ignored_after_newline_in_extend_variable_syntax(self):
          self.varz['${x}'] = 'test string'
          self.varz['${lf}'] = '\\n'
          self.varz['${lfs}'] = '\\n '
          for inp, exp in [('${x.replace(" ", """\\n""")}', 'test\nstring'),
                           ('${x.replace(" ", """\\n """)}', 'test\n string'),
                           ('${x.replace(" ", """${lf}""")}', 'test\nstring'),
                           ('${x.replace(" ", """${lfs}""")}', 'test\n string')]:
              assert_equal(self.varz.replace_scalar(inp), exp)
  
      def test_escaping_with_extended_variable_syntax(self):
          self.varz['${p}'] = 'c:\\temp'
          assert self.varz['${p}'] == 'c:\\temp'
          assert_equal(self.varz.replace_scalar('${p + "\\\\foo.txt"}'),
                       'c:\\temp\\foo.txt')
  
      def test_internal_variables(self):
          # Internal variables are variables like ${my${name}}
          self.varz['${name}'] = 'name'
          self.varz['${my name}'] = 'value'
          assert_equal(self.varz.replace_scalar('${my${name}}'), 'value')
          self.varz['${whos name}'] = 'my'
          assert_equal(self.varz.replace_scalar('${${whos name} ${name}}'), 'value')
          assert_equal(self.varz.replace_scalar('${${whos${name}}${name}}'), 'value')
          self.varz['${my name}'] = [1, 2, 3]
          assert_equal(self.varz.replace_scalar('${${whos${name}}${name}}'), [1, 2, 3])
          assert_equal(self.varz.replace_scalar('- ${${whos${name}}${name}} -'), '- [1, 2, 3] -')
  
      def test_math_with_internal_vars(self):
          assert_equal(self.varz.replace_scalar('${${1}+${2}}'), 3)
          assert_equal(self.varz.replace_scalar('${${1}-${2}}'), -1)
          assert_equal(self.varz.replace_scalar('${${1}*${2}}'), 2)
          assert_equal(self.varz.replace_scalar('${${1}//${2}}'), 0)
  
      def test_math_with_internal_vars_with_spaces(self):
          assert_equal(self.varz.replace_scalar('${${1} + ${2.5}}'), 3.5)
          assert_equal(self.varz.replace_scalar('${${1} - ${2} + 1}'), 0)
          assert_equal(self.varz.replace_scalar('${${1} * ${2} - 1}'), 1)
          assert_equal(self.varz.replace_scalar('${${1} / ${2.0}}'), 0.5)
  
      def test_math_with_internal_vars_does_not_work_if_first_var_is_float(self):
          assert_raises(VariableError, self.varz.replace_scalar, '${${1.1}+${2}}')
          assert_raises(VariableError, self.varz.replace_scalar, '${${1.1} - ${2}}')
          assert_raises(VariableError, self.varz.replace_scalar, '${${1.1} * ${2}}')
          assert_raises(VariableError, self.varz.replace_scalar, '${${1.1}/${2}}')
  
      def test_list_variable_as_scalar(self):
          self.varz['@{name}'] = exp = ['spam', 'eggs']
          assert_equal(self.varz.replace_scalar('${name}'), exp)
          assert_equal(self.varz.replace_list(['${name}', 42]), [exp, 42])
          assert_equal(self.varz.replace_string('${name}'), str(exp))
  
      def test_copy(self):
          varz = Variables()
          varz['${foo}'] = 'bar'
          copy = varz.copy()
          assert_equal(copy['${foo}'], 'bar')
  
      def test_ignore_error(self):
          v = Variables()
          v['${X}'] = 'x'
          v['@{Y}'] = [1, 2, 3]
          for item in ['${foo}', 'foo${bar}', '${foo}', '@{zap}', '${Y}[7]',
                       '${inv', '${{inv}', '${var}[inv', '${var}[key][inv']:
              x_at_end = 'x' if (item.count('{') == item.count('}') and
                                 item.count('[') == item.count(']')) else '${x}'
              assert_equal(v.replace_string(item, ignore_errors=True), item)
              assert_equal(v.replace_string('${x}'+item+'${x}', ignore_errors=True),
                           'x' + item + x_at_end)
              assert_equal(v.replace_scalar(item, ignore_errors=True), item)
              assert_equal(v.replace_scalar('${x}'+item+'${x}', ignore_errors=True),
                           'x' + item + x_at_end)
              assert_equal(v.replace_list([item], ignore_errors=True), [item])
              assert_equal(v.replace_list(['${X}', item, '@{Y}'], ignore_errors=True),
                           ['x', item, 1, 2, 3])
              assert_equal(v.replace_list(['${x}'+item+'${x}', '@{NON}'], ignore_errors=True),
                           ['x' + item + x_at_end, '@{NON}'])
  
      def test_sequence_subscript(self):
          sequences = (
              [42, 'my', 'name'],
              (42, ['foo', 'bar'], 'name'),
              'abcDEF123#@$',
              b'abcDEF123#@$',
              bytearray(b'abcDEF123#@$'),
          )
          for var in sequences:
              self.varz['${var}'] = var
              assert_equal(self.varz.replace_scalar('${var}[0]'), var[0])
              assert_equal(self.varz.replace_scalar('${var}[-2]'), var[-2])
              assert_equal(self.varz.replace_scalar('${var}[::2]'), var[::2])
              assert_equal(self.varz.replace_scalar('${var}[1::2]'), var[1::2])
              assert_equal(self.varz.replace_scalar('${var}[1:-3:2]'), var[1:-3:2])
              assert_raises(VariableError, self.varz.replace_scalar, '${var}[0][1]')
  
      def test_dict_subscript(self):
          a_key = (42, b'key')
          var = {'foo': 'bar', 42: [4, 2], 'name': b'my-name', a_key: {4: 2}}
          self.varz['${a_key}'] = a_key
          self.varz['${var}'] = var
          assert_equal(self.varz.replace_scalar('${var}[foo][-1]'), var['foo'][-1])
          assert_equal(self.varz.replace_scalar('${var}[${42}][-1]'), var[42][-1])
          assert_equal(self.varz.replace_scalar('${var}[name][:3]'), var['name'][:3])
          assert_equal(self.varz.replace_scalar('${var}[${a_key}][${4}]'), var[a_key][4])
          assert_raises(VariableError, self.varz.replace_scalar, '${var}[1]')
          assert_raises(VariableError, self.varz.replace_scalar, '${var}[42:]')
          assert_raises(VariableError, self.varz.replace_scalar, '${var}[nonex]')
  
      def test_custom_class_subscriptable_like_sequence(self):
          # the two class attributes are accessible via indices 0 and 1
          # slicing should be supported here as well
          bytes_key = b'my'
          var = PythonObject([1, 2, 3, 4, 5], {bytes_key: 'myname'})
          self.varz['${bytes_key}'] = bytes_key
          self.varz['${var}'] = var
          assert_equal(self.varz.replace_scalar('${var}[${0}][2::2]'), [3, 5])
          assert_equal(self.varz.replace_scalar('${var}[0][2::2]'), [3, 5])
          assert_equal(self.varz.replace_scalar('${var}[1][${bytes_key}][2:]'), 'name')
          assert_equal(self.varz.replace_scalar('${var}\\[1]'), str(var) + '[1]')
          assert_equal(self.varz.replace_scalar('${var}[:][0][4]'), var[:][0][4])
          assert_equal(self.varz.replace_scalar('${var}[:-2]'), var[:-2])
          assert_equal(self.varz.replace_scalar('${var}[:7:-2]'), var[:7:-2])
          assert_equal(self.varz.replace_scalar('${var}[2::]'), ())
          assert_raises(VariableError, self.varz.replace_scalar, '${var}[${2}]')
          assert_raises(VariableError, self.varz.replace_scalar, '${var}[${bytes_key}]')
  
      def test_non_subscriptable(self):
          assert_raises(VariableError, self.varz.replace_scalar, '${1}[1]')
  
  
  if __name__ == '__main__':
      unittest.main()
  