@@ -505,6 +505,25 @@ def test_collections(self):
505505 # FIXME: referencing problems with the collection class
506506 # self._try_marshalling(jobj, pobj)
507507
508+ def test_linked_hash_map (self ):
509+ """
510+ Tests the handling of LinkedHashMap (issue #30)
511+
512+ The entries of a LinkedHashMap are written in the block data of the
513+ HashMap it extends. Reading that block data twice used to consume
514+ the fields written after the map, and to fail on the way.
515+ """
516+ # A LinkedHashMap written on its own
517+ pobj = javaobj .loads (self .read_file ("testBareLinkedHashMap.ser" ))
518+ self .assertEqual (dict (pobj ), {"a" : "1" , "b" : "2" })
519+
520+ # A LinkedHashMap nested in an object
521+ pobj = javaobj .loads (self .read_file ("testLinkedHashMap.ser" ))
522+ self .assertEqual (pobj .name , "holder" )
523+ self .assertEqual (dict (pobj .settings ), {"first" : "1" , "second" : "2" })
524+ # The field written after the map: it was misread before the fix
525+ self .assertEqual (pobj .port , 443 )
526+
508527 def test_jceks_issue_5 (self ):
509528 """
510529 Tests the handling of JCEKS issue #5
@@ -927,6 +946,47 @@ def test_java_time_zone_offset_large(self):
927946 jt .do_zone_offset (None , struct .pack (">bi" , 127 , 999999 ))
928947 self .assertEqual (jt .offset , 999999 )
929948
949+ def test_java_time_year_month_day (self ):
950+ jt = self ._make_time ()
951+ jt .do_year (None , struct .pack (">i" , 2026 ))
952+ self .assertEqual (jt .year , 2026 )
953+
954+ jt = self ._make_time ()
955+ jt .do_year_month (None , struct .pack (">ib" , 2026 , 8 ))
956+ self .assertEqual ((jt .year , jt .month ), (2026 , 8 ))
957+
958+ jt = self ._make_time ()
959+ jt .do_month_day (None , struct .pack (">bb" , 8 , 12 ))
960+ self .assertEqual ((jt .month , jt .day ), (8 , 12 ))
961+
962+ def test_java_time_period (self ):
963+ jt = self ._make_time ()
964+ jt .do_period (None , struct .pack (">iii" , 1 , 2 , 3 ))
965+ self .assertEqual ((jt .year , jt .month , jt .day ), (1 , 2 , 3 ))
966+
967+ def test_java_time_offset_time (self ):
968+ """An offset time is a local time followed by a zone offset."""
969+ jt = self ._make_time ()
970+ jt .do_offset_time (
971+ None , struct .pack (">bbbi" , 5 , 3 , 2 , 12345 ) + struct .pack (">b" , 4 )
972+ )
973+ self .assertEqual ((jt .hour , jt .minute , jt .second ), (5 , 3 , 2 ))
974+ self .assertEqual (jt .nano , 12345 )
975+ self .assertEqual (jt .offset , 4 * 900 )
976+
977+ def test_java_time_offset_date_time (self ):
978+ """An offset date time is a local date time and a zone offset."""
979+ jt = self ._make_time ()
980+ jt .do_offset_date_time (
981+ None ,
982+ struct .pack (">ibb" , 2026 , 8 , 12 )
983+ + struct .pack (">bbbi" , 5 , 3 , 2 , 12345 )
984+ + struct .pack (">b" , 4 ),
985+ )
986+ self .assertEqual ((jt .year , jt .month , jt .day ), (2026 , 8 , 12 ))
987+ self .assertEqual ((jt .hour , jt .minute , jt .second ), (5 , 3 , 2 ))
988+ self .assertEqual (jt .offset , 4 * 900 )
989+
930990 def test_dunder_methods (self ):
931991 transformer_cls = javaobj .transformers .DefaultObjectTransformer
932992
@@ -951,40 +1011,31 @@ def test_dunder_methods(self):
9511011 jprim .value = 1
9521012 self .assertLess (jprim , 2 )
9531013
954- def test_linked_hash_map_positive (self ):
955- data = (
956- STREAM_MAGIC
957- + _tc (TerminalCode .TC_BLOCKDATA )
958- + struct .pack (">ii" , 16 , 1 )
959- + _tc (TerminalCode .TC_NULL )
960- + _tc (TerminalCode .TC_NULL )
961- + _tc (TerminalCode .TC_ENDBLOCKDATA )
962- + b"\x00 "
963- )
964- um = javaobj .JavaObjectUnmarshaller (BytesIO (data ))
965- lhm = javaobj .transformers .DefaultObjectTransformer .JavaLinkedHashMap (um )
966- lhm .__extra_loading__ (um )
967- self .assertEqual (dict (lhm ), {None : None })
968-
969- def test_linked_hash_map_missing_blockdata (self ):
970- data = STREAM_MAGIC + _tc (TerminalCode .TC_NULL )
971- um = javaobj .JavaObjectUnmarshaller (BytesIO (data ))
972- lhm = javaobj .transformers .DefaultObjectTransformer .JavaLinkedHashMap (um )
973- with self .assertRaises (ValueError ):
974- lhm .__extra_loading__ (um )
975-
976- def test_linked_hash_map_bad_trailing_byte (self ):
977- data = (
978- STREAM_MAGIC
979- + _tc (TerminalCode .TC_BLOCKDATA )
980- + struct .pack (">ii" , 16 , 0 )
981- + _tc (TerminalCode .TC_ENDBLOCKDATA )
982- + b"\x01 "
983- )
984- um = javaobj .JavaObjectUnmarshaller (BytesIO (data ))
985- lhm = javaobj .transformers .DefaultObjectTransformer .JavaLinkedHashMap (um )
986- with self .assertRaises (ValueError ):
987- lhm .__extra_loading__ (um )
1014+ def test_linked_hash_map_loads_from_annotations (self ):
1015+ """
1016+ A LinkedHashMap takes its content from the annotations of its
1017+ HashMap parent, like a HashMap does: the first annotation is the
1018+ block data holding the number of buckets and the size, the next
1019+ ones are the keys and values, one after the other.
1020+ """
1021+ transformer_cls = javaobj .transformers .DefaultObjectTransformer
1022+ lhm = transformer_cls .JavaLinkedHashMap (None )
1023+ lhm .annotations = [
1024+ struct .pack (">ii" , 16 , 2 ),
1025+ "first" ,
1026+ "1" ,
1027+ "second" ,
1028+ "2" ,
1029+ ]
1030+ lhm .__extra_loading__ (None )
1031+ self .assertEqual (dict (lhm ), {"first" : "1" , "second" : "2" })
1032+
1033+ def test_linked_hash_map_empty (self ):
1034+ transformer_cls = javaobj .transformers .DefaultObjectTransformer
1035+ lhm = transformer_cls .JavaLinkedHashMap (None )
1036+ lhm .annotations = [struct .pack (">ii" , 16 , 0 )]
1037+ lhm .__extra_loading__ (None )
1038+ self .assertEqual (dict (lhm ), {})
9881039
9891040
9901041# ------------------------------------------------------------------------------
0 commit comments