text: from io import BytesIO
  from sys import version_info
  from unittest import TestCase
  from xml.etree import ElementTree
  
  import datetime
  import pytest
  
  from pyclarity_lims.constants import nsmap
  from pyclarity_lims.descriptors import StringDescriptor, StringAttributeDescriptor, StringListDescriptor, \
      StringDictionaryDescriptor, IntegerDescriptor, BooleanDescriptor, UdfDictionary, EntityDescriptor, \
      InputOutputMapList, EntityListDescriptor, PlacementDictionary, EntityList, SubTagDictionary, ExternalidList,\
      XmlElementAttributeDict, XmlAttributeList, XmlReagentLabelList, XmlPooledInputDict, XmlAction, QueuedArtifactList
  from pyclarity_lims.entities import Artifact, ProtocolStep, Container, Process, Step
  from pyclarity_lims.lims import Lims
  from tests import elements_equal
  
  if version_info[0] == 2:
      from mock import Mock
  else:
      from unittest.mock import Mock
  
  
  def _tostring(e):
      outfile = BytesIO()
      ElementTree.ElementTree(e).write(outfile, encoding='utf-8', xml_declaration=True)
      return outfile.getvalue().decode("utf-8")
  
  
  class TestDescriptor(TestCase):
      def _make_desc(self, klass, *args, **kwargs):
          return klass(*args, **kwargs)
  
  
  class TestStringDescriptor(TestDescriptor):
      def setUp(self):
          self.et = ElementTree.fromstring("""<?xml version="1.0" encoding="utf-8"?>
  <test-entry>
  <name>test name</name>
  </test-entry>
  """)
          self.instance = Mock(root=self.et)
  
      def test__get__(self):
          sd = self._make_desc(StringDescriptor, 'name')
          assert sd.__get__(self.instance, None) == "test name"
  
      def test__set__(self):
          sd = self._make_desc(StringDescriptor, 'name')
          sd.__set__(self.instance, "new test name")
          assert self.et.find('name').text == "new test name"
  
      def test_create(self):
          instance_new = Mock(root=ElementTree.Element('test-entry'))
          sd = self._make_desc(StringDescriptor, 'name')
          sd.__set__(instance_new, "test name")
          assert instance_new.root.find('name').text == 'test name'
  
  
  class TestIntegerDescriptor(TestDescriptor):
      def setUp(self):
          self.et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <test-entry>
  <count>32</count>
  </test-entry>
  """)
          self.instance = Mock(root=self.et)
  
      def test__get__(self):
          sd = self._make_desc(IntegerDescriptor, 'count')
          assert sd.__get__(self.instance, None) == 32
  
      def test__set__(self):
          sd = self._make_desc(IntegerDescriptor, 'count')
          sd.__set__(self.instance, 23)
          assert self.et.find('count').text == '23'
          sd.__set__(self.instance, '23')
          assert self.et.find('count').text == '23'
  
      def test_create(self):
          instance_new = Mock(root=ElementTree.Element('test-entry'))
          sd = self._make_desc(IntegerDescriptor, 'count')
          sd.__set__(instance_new, 23)
          assert instance_new.root.find('count').text == '23'
  
  
  class TestBooleanDescriptor(TestDescriptor):
      def setUp(self):
          self.et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <test-entry>
  <istest>true</istest>
  </test-entry>
  """)
          self.instance = Mock(root=self.et)
  
      def test__get__(self):
          bd = self._make_desc(BooleanDescriptor, 'istest')
          assert bd.__get__(self.instance, None)
  
      def test__set__(self):
          bd = self._make_desc(BooleanDescriptor, 'istest')
          bd.__set__(self.instance, False)
          assert self.et.find('istest').text == 'false'
          bd.__set__(self.instance, 'true')
          assert self.et.find('istest').text == 'true'
  
      def test_create(self):
          instance_new = Mock(root=ElementTree.Element('test-entry'))
          bd = self._make_desc(BooleanDescriptor, 'istest')
          bd.__set__(instance_new, True)
          assert instance_new.root.find('istest').text == 'true'
  
  
  class TestEntityDescriptor(TestDescriptor):
      def setUp(self):
          self.et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <test-entry>
  <artifact uri="http://testgenologics.com:4040/api/v2/artifacts/a1"></artifact>
  </test-entry>
  """)
          self.lims = Lims('http://testgenologics.com:4040', username='test', password='password')
          self.a1 = Artifact(self.lims, id='a1')
          self.a2 = Artifact(self.lims, id='a2')
          self.instance = Mock(root=self.et, lims=self.lims)
  
      def test__get__(self):
          ed = self._make_desc(EntityDescriptor, 'artifact', Artifact)
          assert ed.__get__(self.instance, None) == self.a1
  
      def test__set__(self):
          ed = self._make_desc(EntityDescriptor, 'artifact', Artifact)
          ed.__set__(self.instance, self.a2)
          assert self.et.find('artifact').attrib['uri'] == 'http://testgenologics.com:4040/api/v2/artifacts/a2'
  
      def test_create(self):
          instance_new = Mock(root=ElementTree.Element('test-entry'))
          ed = self._make_desc(EntityDescriptor, 'artifact', Artifact)
          ed.__set__(instance_new, self.a1)
          assert instance_new.root.find('artifact').attrib['uri'] == 'http://testgenologics.com:4040/api/v2/artifacts/a1'
  
  
  class TestEntityListDescriptor(TestDescriptor):
      def setUp(self):
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <test-entry>
  <artifact uri="http://testgenologics.com:4040/api/v2/artifacts/a1"></artifact>
  <artifact uri="http://testgenologics.com:4040/api/v2/artifacts/a2"></artifact>
  </test-entry>
  """)
          self.lims = Lims('http://testgenologics.com:4040', username='test', password='password')
          self.a1 = Artifact(self.lims, id='a1')
          self.a2 = Artifact(self.lims, id='a2')
          self.instance1 = Mock(root=et, lims=self.lims)
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <test-entry>
  <nesting>
  <artifact uri="http://testgenologics.com:4040/api/v2/artifacts/a1"></artifact>
  <artifact uri="http://testgenologics.com:4040/api/v2/artifacts/a2"></artifact>
  </nesting>
  </test-entry>
          """)
          self.instance2 = Mock(root=et, lims=self.lims)
  
      def test__get__(self):
          ed = self._make_desc(EntityListDescriptor, 'artifact', Artifact)
          assert ed.__get__(self.instance1, None) == [self.a1, self.a2]
          ed = self._make_desc(EntityListDescriptor, 'artifact', Artifact, nesting=['nesting'])
          assert ed.__get__(self.instance2, None) == [self.a1, self.a2]
  
  
  class TestStringAttributeDescriptor(TestDescriptor):
      def setUp(self):
          self.et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <test-entry name="test name">
  </test-entry>""")
          self.instance = Mock(root=self.et)
  
      def test__get__(self):
          sd = self._make_desc(StringAttributeDescriptor, 'name')
          assert sd.__get__(self.instance, None) == "test name"
  
      def test__set__(self):
          sd = self._make_desc(StringAttributeDescriptor, 'name')
          sd.__set__(self.instance, "test name2")
          assert self.et.attrib['name'] == "test name2"
  
      def test_create(self):
          instance_new = Mock(root=ElementTree.Element('test-entry'))
          bd = self._make_desc(StringAttributeDescriptor, 'name')
          bd.__set__(instance_new, "test name2")
          assert instance_new.root.attrib['name'] == "test name2"
  
  
  class TestStringListDescriptor(TestDescriptor):
      def setUp(self):
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <test-entry>
  <test-subentry>A01</test-subentry>
  <test-subentry>B01</test-subentry>
  </test-entry>""")
          self.instance1 = Mock(root=et)
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <test-entry>
  <nesting>
  <test-subentry>A01</test-subentry>
  <test-subentry>B01</test-subentry>
  </nesting>
  </test-entry>""")
          self.instance2 = Mock(root=et)
  
      def test__get__(self):
          sd = self._make_desc(StringListDescriptor, 'test-subentry')
          assert sd.__get__(self.instance1, None) == ['A01', 'B01']
          sd = self._make_desc(StringListDescriptor, 'test-subentry', nesting=['nesting'])
          assert sd.__get__(self.instance2, None) == ['A01', 'B01']
  
      def test__set__(self):
          sd = self._make_desc(StringListDescriptor, 'test-subentry')
          sd.__set__(self.instance1, ['A02', 'B02'])
          res = sd.__get__(self.instance1, None)
          assert isinstance(res, list)
          assert res == ['A02', 'B02']
  
  
  class TestStringDictionaryDescriptor(TestDescriptor):
      def setUp(self):
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <test-entry>
  <test-subentry>
  <test-firstkey/>
  <test-secondkey>second value</test-secondkey>
  </test-subentry>
  </test-entry>""")
          self.instance = Mock(root=et)
  
      def test__get__(self):
          sd = self._make_desc(StringDictionaryDescriptor, 'test-subentry')
          res = sd.__get__(self.instance, None)
          assert isinstance(res, dict)
          assert res['test-firstkey'] is None
          assert res['test-secondkey'] == 'second value'
  
      def test__set__(self):
          sd = self._make_desc(StringDictionaryDescriptor, 'test-subentry')
          sd.__set__(self.instance, {'mykey1': 'myvalue1'})
          res = sd.__get__(self.instance, None)
          assert isinstance(res, dict)
          assert res['mykey1'] == 'myvalue1'
  
  
  class TestUdfDictionary(TestCase):
      def setUp(self):
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <test-entry xmlns:udf="http://genologics.com/ri/userdefined">
  <udf:field type="String" name="test">stuff</udf:field>
  <udf:field type="Numeric" name="how much">42</udf:field>
  <udf:field type="Boolean" name="really?">true</udf:field>
  </test-entry>""")
          self.instance1 = Mock(root=et)
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <test-entry xmlns:udf="http://genologics.com/ri/userdefined">
  <nesting>
  <udf:field type="String" name="test">stuff</udf:field>
  <udf:field type="Numeric" name="how much">42</udf:field>
  <udf:field type="Boolean" name="really?">true</udf:field>
  </nesting>
  </test-entry>""")
          self.instance2 = Mock(root=et)
          self.dict1 = UdfDictionary(self.instance1)
          self.dict2 = UdfDictionary(self.instance2, nesting=['nesting'])
          self.dict_fail = UdfDictionary(self.instance2)
  
          self.empty_et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
          <test-entry xmlns:udf="http://genologics.com/ri/userdefined">
          </test-entry>""")
  
      def _get_udf_value(self, udf_dict, key):
          for e in udf_dict._elems:
              if e.attrib['name'] != key:
                  continue
              else:
                  return e.text
  
      def test___getitem__(self):
          assert self.dict1.__getitem__('test') == self._get_udf_value(self.dict1, 'test')
          assert self.dict2.__getitem__('test') == self._get_udf_value(self.dict2, 'test')
          self.assertRaises(KeyError, self.dict_fail.__getitem__, 'test')
  
      def test___setitem__(self):
          assert self._get_udf_value(self.dict1, 'test') == 'stuff'
          self.dict1.__setitem__('test', 'other')
          assert self._get_udf_value(self.dict1, 'test') == 'other'
  
          assert self._get_udf_value(self.dict1, 'how much') == '42'
          self.dict1.__setitem__('how much', 21)
          assert self._get_udf_value(self.dict1, 'how much') == '21'
  
          assert self._get_udf_value(self.dict1, 'really?') == 'true'
          self.dict1.__setitem__('really?', False)
          assert self._get_udf_value(self.dict1, 'really?') == 'false'
  
          self.assertRaises(TypeError, self.dict1.__setitem__, 'how much', '433')
  
          # FIXME: I'm not sure if this is the expected behaviour
          self.dict1.__setitem__('how much', None)
          assert self._get_udf_value(self.dict1, 'how much') == b'None'
  
          assert self._get_udf_value(self.dict2, 'test') == 'stuff'
          self.dict2.__setitem__('test', 'other')
          assert self._get_udf_value(self.dict2, 'test') == 'other'
  
      def test___setitem__new(self):
          self.dict1.__setitem__('new string', 'new stuff')
          assert self._get_udf_value(self.dict1, 'new string') == 'new stuff'
  
          self.dict1.__setitem__('new numeric', 21)
          assert self._get_udf_value(self.dict1, 'new numeric') == '21'
  
          self.dict1.__setitem__('new bool', False)
          assert self._get_udf_value(self.dict1, 'new bool') == 'false'
  
          self.dict2.__setitem__('new string', 'new stuff')
          assert self._get_udf_value(self.dict2, 'new string') == 'new stuff'
  
      def test___setitem__unicode(self):
          assert self._get_udf_value(self.dict1, 'test') == 'stuff'
          self.dict1.__setitem__('test', u'unicode')
          assert self._get_udf_value(self.dict1, 'test') == 'unicode'
  
          self.dict1.__setitem__(u'test', 'unicode2')
          assert self._get_udf_value(self.dict1, 'test') == 'unicode2'
  
      def test_create(self):
          instance = Mock(root=self.empty_et)
          dict1 = UdfDictionary(instance)
          dict1['test'] = 'value1'
          assert self._get_udf_value(dict1, 'test') == 'value1'
  
      def test_create_with_nesting(self):
          instance = Mock(root=self.empty_et)
          dict1 = UdfDictionary(instance, nesting=['cocoon'])
          dict1['test'] = 'value1'
          assert self._get_udf_value(dict1, 'test') == 'value1'
  
      def test___delitem__(self):
          assert self.dict1['test'] == self._get_udf_value(self.dict1, 'test')
          del self.dict1['test']
          with pytest.raises(KeyError):
              _ = self.dict1['test']
          assert self._get_udf_value(self.dict1, 'test') is None
  
      def test_items(self):
          pass
  
      def test_clear(self):
          assert self.dict1
          self.dict1.clear()
          assert not self.dict1
          assert len(self.dict1) == 0
  
      def test___iter__(self):
          expected_content = [
              ("test", "stuff"),
              ("really?", True),
              ("how much", 42)
          ]
          for k in self.dict1:
              assert (k, self.dict1[k]) in expected_content
  
  
  class TestPlacementDictionary(TestDescriptor):
  
      def setUp(self):
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <test-entry xmlns:udf="http://genologics.com/ri/userdefined">
  <placement uri="http://testgenologics.com:4040/api/v2/artifacts/a1" limsid="a1">
  <value>A:1</value>
  </placement>
  <other>thing</other>
  </test-entry>""")
          self.lims = Lims('http://testgenologics.com:4040', username='test', password='password')
          self.instance1 = Mock(root=et, lims=self.lims)
          self.dict1 = PlacementDictionary(self.instance1)
          self.art1 = Artifact(lims=self.lims, id='a1')
  
      def test___getitem__(self):
          assert self.dict1['A:1'] == self.art1
  
      def test___setitem__(self):
          assert len(self.dict1.rootnode(self.dict1.instance).findall('placement')) == 1
          art2 = Artifact(lims=self.lims, id='a2')
          self.dict1['A:1'] = art2
          assert len(self.dict1.rootnode(self.dict1.instance).findall('placement')) == 1
  
          self.dict1['A:2'] = art2
          assert len(self.dict1.rootnode(self.dict1.instance).findall('placement')) == 2
          assert self.dict1['A:2'] == art2
  
      def test___setitem__2(self):
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
          <test-entry xmlns:udf="http://genologics.com/ri/userdefined">
          </test-entry>""")
          instance = Mock(root=et, lims=self.lims)
          d = PlacementDictionary(instance)
          assert len(d.rootnode(d.instance).findall('placement')) == 0
          d['A:1'] = self.art1
          assert len(d.rootnode(d.instance).findall('placement')) == 1
  
      def test___delitem__(self):
          assert len(self.dict1.rootnode(self.dict1.instance).findall('placement')) == 1
          del self.dict1['A:1']
          assert len(self.dict1.rootnode(self.dict1.instance).findall('placement')) == 0
  
      def test_clear(self):
          sd = self._make_desc(StringDescriptor, 'other')
          assert sd.__get__(self.instance1, None) == "thing"
          assert len(self.dict1.rootnode(self.dict1.instance).findall('placement')) == 1
          self.dict1.clear()
          assert len(self.dict1.rootnode(self.dict1.instance).findall('placement')) == 0
          assert sd.__get__(self.instance1, None) == "thing"
  
  
  class TestSubTagDictionary(TestCase):
      def setUp(self):
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <test-entry xmlns:udf="http://genologics.com/ri/userdefined">
  <test-tag>
  <key1>value1</key1>
  </test-tag>
  </test-entry>""")
          self.lims = Lims('http://testgenologics.com:4040', username='test', password='password')
          self.instance1 = Mock(root=et, lims=self.lims)
          self.dict1 = SubTagDictionary(self.instance1, tag='test-tag')
  
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
          <test-entry xmlns:udf="http://genologics.com/ri/userdefined">
          </test-entry>""")
          self.instance2 = Mock(root=et, lims=self.lims)
          self.dict2 = SubTagDictionary(self.instance2, tag='test-tag')
  
      def test___getitem__(self):
          assert self.dict1['key1'] == 'value1'
  
      def test___setitem__(self):
          assert len(self.dict1.rootnode(self.dict1.instance)) == 1
          assert self.dict1.rootnode(self.dict1.instance).find('key1').text == 'value1'
          self.dict1['key1'] = 'value11'
          assert len(self.dict1.rootnode(self.dict1.instance)) == 1
          assert self.dict1.rootnode(self.dict1.instance).find('key1').text == 'value11'
          self.dict1['key2'] = 'value2'
          assert len(self.dict1.rootnode(self.dict1.instance)) == 2
          assert self.dict1.rootnode(self.dict1.instance).find('key2').text == 'value2'
          assert self.dict1['key2'] == 'value2'
  
      def test___setitem__from_empty(self):
          assert len(self.dict2.rootnode(self.dict2.instance)) == 0
          self.dict2['key1'] = 'value1'
          assert self.dict2.rootnode(self.dict2.instance).find('key1').text == 'value1'
          assert len(self.dict2.rootnode(self.dict2.instance)) == 1
  
  
  class TestXmlElementAttributeDict(TestCase):
      def setUp(self):
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <test-entry xmlns:udf="http://genologics.com/ri/userdefined">
      <test-tag attrib1="value1" attrib2="value2"/>
      <test-tag attrib1="value11" attrib2="value12" attrib3="value13"/>
      </test-entry>""")
          self.lims = Lims('http://testgenologics.com:4040', username='test', password='password')
          self.instance1 = Mock(root=et, lims=self.lims)
          self.dict1 = XmlElementAttributeDict(self.instance1, tag='test-tag', position=0)
          self.dict2 = XmlElementAttributeDict(self.instance1, tag='test-tag', position=1)
  
      def test___getitem__(self):
          assert self.dict1['attrib1'] == 'value1'
          assert self.dict2['attrib1'] == 'value11'
  
      def test__len__(self):
          assert len(self.dict1) == 2
          assert len(self.dict2) == 3
  
      def test___setitem__(self):
          assert self.dict1['attrib1'] == 'value1'
          assert self.dict1.rootnode(self.dict1.instance).findall('test-tag')[0].attrib['attrib1'] == 'value1'
          self.dict1['attrib1'] = 'value2'
          assert self.dict1.rootnode(self.dict1.instance).findall('test-tag')[0].attrib['attrib1'] == 'value2'
  
  
  class TestXmlPooledInputDict(TestCase):
      def setUp(self):
          et = ElementTree.fromstring('''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
          <test-entry>
          <pooled-inputs>
          <pool output-uri="{uri}/out1" name="pool1">
          <input uri="{uri}/in1"/>
          <input uri="{uri}/in2"/>
          </pool>
          <pool output-uri="{uri}/out2" name="pool2">
          <input uri="{uri}/in3"/>
          <input uri="{uri}/in4"/>
          </pool>
          </pooled-inputs>
          </test-entry>'''.format(uri='http://testgenologics.com:4040'))
  
          self.lims = Lims('http://testgenologics.com:4040', username='test', password='password')
          self.instance1 = Mock(root=et, lims=self.lims)
          self.dict1 = XmlPooledInputDict(self.instance1)
  
          self.out1 = Artifact(self.lims, uri='http://testgenologics.com:4040/out1')
          self.in1 = Artifact(self.lims, uri='http://testgenologics.com:4040/in1')
          self.in2 = Artifact(self.lims, uri='http://testgenologics.com:4040/in2')
  
      def test___getitem__(self):
          assert self.dict1['pool1'] == (self.out1, (self.in1, self.in2))
  
      def test___setitem1__(self):
          assert len(self.dict1) == 2
          assert len(self.dict1.rootnode(self.dict1.instance)) == 2
          # This works in the test but does not work in reality because
          # the pool artifact needs to be creaated by the LIMS.
          self.dict1['pool3'] = (self.out1, (self.in1, self.in2))
          assert len(self.dict1) == 3
          assert len(self.dict1.rootnode(self.dict1.instance)) == 3
  
      def test___setitem2__(self):
          assert len(self.dict1) == 2
          assert len(self.dict1.rootnode(self.dict1.instance)) == 2
  
          # This is the correct way of creating a pool from scratch
          self.dict1['pool3'] = (None, (self.in1, self.in2))
          assert len(self.dict1) == 3
          assert len(self.dict1.rootnode(self.dict1.instance)) == 3
  
  
  class TestEntityList(TestDescriptor):
      def setUp(self):
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <test-entry>
      <artifact uri="http://testgenologics.com:4040/api/v2/artifacts/a1"></artifact>
      <artifact uri="http://testgenologics.com:4040/api/v2/artifacts/a2"></artifact>
      <other>thing</other>
      </test-entry>
      """)
          self.lims = Lims('http://testgenologics.com:4040', username='test', password='password')
          self.a1 = Artifact(self.lims, id='a1')
          self.a2 = Artifact(self.lims, id='a2')
          self.instance1 = Mock(root=et, lims=self.lims)
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <test-entry>
      <nesting>
      <artifact uri="http://testgenologics.com:4040/api/v2/artifacts/a1"></artifact>
      <artifact uri="http://testgenologics.com:4040/api/v2/artifacts/a2"></artifact>
      </nesting>
      </test-entry>
              """)
          self.instance2 = Mock(root=et, lims=self.lims)
  
      def test__get__(self):
          el = EntityList(self.instance1, 'artifact', Artifact)
          assert el[0] == self.a1
          assert el[1] == self.a2
          el = EntityList(self.instance2, 'artifact', Artifact, nesting=['nesting'])
          assert el[0] == self.a1
          assert el[1] == self.a2
  
      def test_append(self):
          el = EntityList(self.instance1, 'artifact', Artifact)
          assert len(el) == 2
          assert len(el.instance.root.findall('artifact')) == 2
          a3 = Artifact(self.lims, id='a3')
          el.append(a3)
          assert len(el) == 3
          assert el[2] == a3
          assert len(el._elems) == 3
          assert len(el.instance.root.findall('artifact')) == 3
  
      def test_insert(self):
          el = EntityList(self.instance1, 'artifact', Artifact)
          assert len(el) == 2
          assert len(el.instance.root.findall('artifact')) == 2
          a3 = Artifact(self.lims, id='a3')
          el.insert(1, a3)
          assert len(el) == 3
          assert el[1] == a3
          assert el[2] == self.a2
          assert len(el._elems) == 3
          assert len(el.instance.root.findall('artifact')) == 3
  
      def test_set(self):
          el = EntityList(self.instance1, 'artifact', Artifact)
          assert len(el) == 2
          assert len(el.instance.root.findall('artifact')) == 2
          a3 = Artifact(self.lims, id='a3')
          el[1] = a3
          assert len(el) == 2
          assert el[1] == a3
          assert len(el._elems) == 2
          assert el.instance.root.findall('artifact')[1].attrib['uri'] == 'http://testgenologics.com:4040/api/v2/artifacts/a3'
  
      def test_set_list(self):
          el = EntityList(self.instance1, 'artifact', Artifact)
          assert len(el) == 2
          assert len(el.instance.root.findall('artifact')) == 2
          a3 = Artifact(self.lims, id='a3')
          a4 = Artifact(self.lims, id='a4')
          el[0:2] = [a3, a4]
          assert len(el) == 2
          assert el[0] == a3
          assert el[1] == a4
  
      def test_clear(self):
          el = EntityList(self.instance1, 'artifact', Artifact)
          sd = self._make_desc(StringDescriptor, 'other')
          assert sd.__get__(self.instance1, None) == "thing"
          assert len(el) == 2
          el.clear()
          assert len(el) == 0
          assert sd.__get__(self.instance1, None) == "thing"
  
      def test___add__(self):
          el1 = EntityList(self.instance1, 'artifact', Artifact)
          assert len(el1) == 2
          assert len(el1.instance.root.findall('artifact')) == 2
          el2 = [Artifact(self.lims, id='a3'), Artifact(self.lims, id='a4')]
  
          el3 = el1 + el2
          assert len(el3) == 4
          assert el3[:2] == el1
          assert el3[2:] == el2
  
      def test__iadd__(self):
          el1 = EntityList(self.instance1, 'artifact', Artifact)
          id1 = id(el1)
          assert len(el1) == 2
          assert len(el1.instance.root.findall('artifact')) == 2
          el2 = [Artifact(self.lims, id='a3'), Artifact(self.lims, id='a4')]
  
          el1 += el2
          id2 = id(el1)
          assert id1 == id2  # still the same object
          assert len(el1) == 4
          assert el1[2:] == el2
  
  
  class TestInputOutputMapList(TestCase):
      def setUp(self):
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <test-entry xmlns:udf="http://genologics.com/ri/userdefined">
  <input-output-map>
  <input uri="http://testgenologics.com:4040/api/v2/artifacts/1" limsid="1">
  <parent-process uri="http://testgenologics.com:4040//api/v2/processes/1" limsid="1"/>
  </input>
  <output uri="http://testgenologics.com:4040/api/v2/artifacts/2" output-generation-type="PerAllInputs" output-type="ResultFile" limsid="2"/>
  </input-output-map>
  </test-entry>""")
          self.instance1 = Mock(root=et, lims=Mock(cache={}))
          self.IO_map = InputOutputMapList()
  
      def test___get__(self):
          expected_keys_input = ['limsid', 'parent-process', 'uri']
          expected_keys_ouput = ['limsid', 'output-type', 'output-generation-type', 'uri']
          res = self.IO_map.__get__(self.instance1, None)
          assert sorted(res[0][0].keys()) == sorted(expected_keys_input)
          assert sorted(res[0][1].keys()) == sorted(expected_keys_ouput)
  
      def test_create(self):
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
          <test-entry xmlns:udf="http://genologics.com/ri/userdefined">
          </test-entry>""")
          lims = Mock(cache={})
          instance = Mock(root=et, lims=lims)
          res = self.IO_map.__get__(instance, None)
          input_dict = {'uri': Artifact(lims, uri='input_uri'), 'limsid': 'a1', 'parent-process': Process(lims, uri='p_uri')}
          output_dict = {'uri': Artifact(lims, uri='output_uri'), 'limsid': 'a2', 'output-type': 'PerInput'}
          res.append((input_dict, output_dict))
          assert len(et) == 1
          node = et.find('input-output-map')
          assert len(node) == 2  # input and output
          assert node.find('input').attrib['uri'] == 'input_uri'
          assert node.find('input').attrib['limsid'] == 'a1'
          assert node.find('input').find('parent-process').attrib['uri'] == 'p_uri'
          assert node.find('output').attrib['uri'] == 'output_uri'
          assert node.find('output').attrib['limsid'] == 'a2'
          assert node.find('output').attrib['output-type'] == 'PerInput'
  
  
  class TestExternalidList(TestCase):
      def setUp(self):
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <test-entry>
      <ri:externalid xmlns:ri="http://genologics.com/ri" id="1" uri="http://testgenologics.com:4040/api/v2/external/1" />
      <ri:externalid xmlns:ri="http://genologics.com/ri" id="2" uri="http://testgenologics.com:4040/api/v2/external/2" />
      </test-entry>
      """)
          self.lims = Lims('http://testgenologics.com:4040', username='test', password='password')
          self.instance1 = Mock(root=et, lims=self.lims)
  
      def test_get(self):
          el = ExternalidList(self.instance1)
          assert len(el) == 2
          assert el[0] == ("1", "http://testgenologics.com:4040/api/v2/external/1")
          assert el[1] == ("2", "http://testgenologics.com:4040/api/v2/external/2")
  
      def test_append(self):
          el = ExternalidList(self.instance1)
          assert len(el) == 2
          el.append(("3", "http://testgenologics.com:4040/api/v2/external/3"))
          assert len(el) == 3
          assert el[2] == ("3", "http://testgenologics.com:4040/api/v2/external/3")
          assert len(el._elems) == 3
          elem = el.instance.root.findall(nsmap('ri:externalid'))
          assert elem[2].attrib['id'] == '3'
          assert elem[2].attrib['uri'] == 'http://testgenologics.com:4040/api/v2/external/3'
  
  
  class TestXmlAttributeList(TestCase):
      def setUp(self):
          et = ElementTree.fromstring("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <test-entry>
      <test-tags>
      <test-tag attrib1="value1" attrib2="value2"/>
      <test-tag attrib1="value11" attrib2="value12" attrib3="value13"/>
      </test-tags>
      </test-entry>
      """)
          self.lims = Lims('http://testgenologics.com:4040', username='test', password='password')
          self.instance1 = Mock(root=et, lims=self.lims)
  
      def test_get(self):
          al = XmlAttributeList(self.instance1, tag='test-tag', nesting=['test-tags'])
          assert al[0] == {'attrib1': 'value1', 'attrib2': 'value2'}
          assert al[1] == {'attrib1': 'value11', 'attrib2': 'value12', 'attrib3': 'value13'}
  
      def test_append(self):
          el = XmlAttributeList(self.instance1, tag='test-tag', nesting=['test-tags'])
          el.append({'attrib1': 'value21'})
          elements_equal(
              el.instance.root.find('test-tags').findall('test-tag')[-1],
              ElementTree.fromstring('''<test-tag attrib1="value21" />''')
          )
  
      def test_insert(self):
          el = XmlAttributeList(self.instance1, tag='test-tag', nesting=['test-tags'])
          el.insert(1, {'attrib1': 'value21'})
          elements_equal(
              el.instance.root.find('test-tags').findall('test-tag')[1],
              ElementTree.fromstring('''<test-tag attrib1="value21" />''')
          )
          elements_equal(
              el.instance.root.find('test-tags').findall('test-tag')[2],
              ElementTree.fromstring('''<test-tag attrib1="value11" attrib2="value12" attrib3="value13" />''')
          )
  
  
  class TestXmlReagentLabelList(TestCase):
      def setUp(self):
          et = ElementTree.fromstring('''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
          <test-entry>
          <reagent-label name="label name"/>
          </test-entry>''')
  
          self.lims = Lims('http://testgenologics.com:4040', username='test', password='password')
          self.instance1 = Mock(root=et, lims=self.lims)
  
      def test_get(self):
          ll = XmlReagentLabelList(self.instance1)
          assert ll == ['label name']
  
      def test_append(self):
          rl = XmlReagentLabelList(self.instance1)
          rl.append('another label')
          assert rl == ['label name', 'another label']
          elements_equal(
              rl.instance.root.findall('reagent-label')[1],
              ElementTree.fromstring('''<reagent-label name="another label"/>''')
          )
  
  
  class TestXmlAction(TestCase):
      def setUp(self):
          et = ElementTree.fromstring('''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
                  <test-entry>
                  <next-action step-uri="{url}/prt/1/stp/1" rework-step-uri="{url}/steps/1" action="nextstep" artifact-uri="{url}/arts/a1"/>
                  </test-entry>'''.format(url='http://testgenologics.com:4040'))
  
          et1 = ElementTree.fromstring('''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
          <test-entry>
          <next-action artifact-uri="{url}/arts/a1"/>
          </test-entry>'''.format(url='http://testgenologics.com:4040'))
  
          self.lims = Lims('http://testgenologics.com:4040', username='test', password='password')
          self.instance1 = Mock(root=et, lims=self.lims)
          self.instance_empty = Mock(root=et1, lims=self.lims)
  
      def test_parse(self):
          action = XmlAction(self.instance1, tag='next-action')
          assert action['action'] == 'nextstep'
          assert action['step'] == ProtocolStep(self.lims, uri='http://testgenologics.com:4040/prt/1/stp/1')
          assert action['artifact'] == Artifact(self.lims, uri='http://testgenologics.com:4040/arts/a1')
          assert action['rework-step'] == Step(self.lims, uri='http://testgenologics.com:4040/steps/1')
  
      def test_set(self):
          action = XmlAction(self.instance_empty, tag='next-action')
          action['step'] = ProtocolStep(self.lims, uri='http://testgenologics.com:4040/prt/1/stp/1')
          assert action.instance.root.find('next-action').attrib['step-uri'] == 'http://testgenologics.com:4040/prt/1/stp/1'
          action['action'] = 'nextstep'
          assert action.instance.root.find('next-action').attrib['action'] == 'nextstep'
          action['rework-step'] = Step(self.lims, uri='http://testgenologics.com:4040/steps/1')
          assert action.instance.root.find('next-action').attrib['rework-step-uri'] == 'http://testgenologics.com:4040/steps/1'
  
          with pytest.raises(KeyError):
              action['whatever'] = 'youwant'
  
  
  class TestQueuedArtifactList(TestCase):
      def setUp(self):
          queue_txt = '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
                  <test-entry>
                  <artifacts>
                  <artifact uri="{url}/artifacts/a1">
                  <queue-time>2011-12-25T01:10:10.050+00:00</queue-time>
                  <location>
                  <container uri="{url}/containers/c1"/>
                  <value>A:1</value>
                  </location>
                  </artifact>
                  <artifact uri="{url}/artifacts/a2">
                  <queue-time>2011-12-25T01:10:10.200+01:00</queue-time>
                  <location>
                  <container uri="{url}/containers/c1"/>
                  <value>A:2</value>
                  </location>
                  </artifact>
                  <artifact uri="{url}/artifacts/a3">
                  <queue-time>2011-12-25T01:10:10.050-01:00</queue-time>
                  <location>
                  <container uri="{url}/containers/c1"/>
                  <value>A:3</value>
                  </location>
                  </artifact>
                  </artifacts>
                  </test-entry>'''
  
  
          self.et_page1 = ElementTree.fromstring('''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
                                  <test-entry>
                                  <artifacts>
                                  <artifact uri="{url}/artifacts/a1">
                                  <queue-time>2011-12-25T01:10:10.050+00:00</queue-time>
                                  <location>
                                  <container uri="{url}/containers/c1"/>
                                  <value>A:1</value>
                                  </location>
                                  </artifact>
                                  </artifacts>
                                  <next-page uri="{url}/queues/q1?page2=500"/>
                                  </test-entry>'''.format(url='http://testgenologics.com:4040/api/v2'))
          self.et_page2 = ElementTree.fromstring('''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
                                  <test-entry> 
                                  <artifacts>
                                  <artifact uri="{url}/artifacts/a2">
                                  <queue-time>2011-12-25T01:10:10.200+01:00</queue-time>
                                  <location>
                                  <container uri="{url}/containers/c1"/>
                                  <value>A:2</value>
                                  </location>
                                  </artifact>
                                  </artifacts>
                                  <next-page uri="{url}/queues/q1?page3=500"/>
                                  </test-entry>'''.format(url='http://testgenologics.com:4040/api/v2'))
          self.et_page3 = ElementTree.fromstring('''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
                                  <test-entry>
                                  <artifacts>
                                  <artifact uri="{url}/artifacts/a3">
                                  <queue-time>2011-12-25T01:10:10.050-01:00</queue-time>
                                  <location>
                                  <container uri="{url}/containers/c1"/>
                                  <value>A:3</value>
                                  </location>
                                  </artifact>
                                  </artifacts>
                                  </test-entry>'''.format(url='http://testgenologics.com:4040/api/v2'))
          et = ElementTree.fromstring(queue_txt.format(url='http://testgenologics.com:4040/api/v2'))
  
          self.lims = Lims('http://testgenologics.com:4040', username='test', password='password')
          self.instance1 = Mock(root=et, lims=self.lims)
          self.instance2 = Mock(root=self.et_page1, lims=self.lims)
  
      def get_queue_art(self, art_id, pos, microsec, time_delta):
          if version_info[0] == 2:
              return (
                  Artifact(self.lims, id=art_id),
                  datetime.datetime(2011, 12, 25, 1, 10, 10, microsec),
                  (Container(self.lims, id='c1'), pos)
              )
          else:
              return (
                  Artifact(self.lims, id=art_id),
                  datetime.datetime(2011, 12, 25, 1, 10, 10, microsec, tzinfo=datetime.timezone(time_delta)),
                  (Container(self.lims, id='c1'), pos)
              )
  
      def test_parse(self):
          queued_artifacts = QueuedArtifactList(self.instance1)
          qart = self.get_queue_art('a1', 'A:1', 50000, datetime.timedelta(0, 0))
          assert queued_artifacts[0] == qart
          qart = self.get_queue_art('a2', 'A:2', 200000, datetime.timedelta(0, 3600))
          assert queued_artifacts[1] == qart
          qart = self.get_queue_art('a3', 'A:3', 50000, datetime.timedelta(0, -3600))
          assert queued_artifacts[2] == qart
  
      def test_set(self):
          queued_artifacts = QueuedArtifactList(self.instance1)
          qart = self.get_queue_art('a1', 'A:4',  50000, datetime.timedelta(0, 0))
          with pytest.raises(NotImplementedError):
              queued_artifacts.append(qart)
  
      def test_parse_multipage(self):
          self.lims.get = Mock(side_effect=[self.et_page2, self.et_page3])
          queued_artifacts = QueuedArtifactList(self.instance2)
          qart = self.get_queue_art('a1', 'A:1', 50000, datetime.timedelta(0, 0))
          assert queued_artifacts[0] == qart
          qart = self.get_queue_art('a2', 'A:2', 200000, datetime.timedelta(0, 3600))
          assert queued_artifacts[1] == qart
          qart = self.get_queue_art('a3', 'A:3', 50000, datetime.timedelta(0, -3600))
          assert queued_artifacts[2] == qart
  
  
  