Edit

kc3-lang/harfbuzz/src/test-repacker.cc

Branch :

  • Show log

    Commit

  • Author : Garret Rieger
    Date : 2021-09-23 14:45:20
    Hash : 5bfc7d10
    Message : [repacker] remove VirtualOffset struct. Make and add_virtual_link () specialization of add_link() instead.

  • src/test-repacker.cc
  • /*
     * Copyright © 2020  Google, Inc.
     *
     *  This is part of HarfBuzz, a text shaping library.
     *
     * Permission is hereby granted, without written agreement and without
     * license or royalty fees, to use, copy, modify, and distribute this
     * software and its documentation for any purpose, provided that the
     * above copyright notice and the following two paragraphs appear in
     * all copies of this software.
     *
     * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     * DAMAGE.
     *
     * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     *
     * Google Author(s): Garret Rieger
     */
    
    #include <string>
    
    #include "hb-repacker.hh"
    #include "hb-open-type.hh"
    
    static void start_object(const char* tag,
                             unsigned len,
                             hb_serialize_context_t* c)
    {
      c->push ();
      char* obj = c->allocate_size<char> (len);
      strncpy (obj, tag, len);
    }
    
    
    static unsigned add_object(const char* tag,
                               unsigned len,
                               hb_serialize_context_t* c)
    {
      start_object (tag, len, c);
      return c->pop_pack (false);
    }
    
    
    static void add_offset (unsigned id,
                            hb_serialize_context_t* c)
    {
      OT::Offset16* offset = c->start_embed<OT::Offset16> ();
      c->extend_min (offset);
      c->add_link (*offset, id);
    }
    
    static void add_wide_offset (unsigned id,
                                 hb_serialize_context_t* c)
    {
      OT::Offset32* offset = c->start_embed<OT::Offset32> ();
      c->extend_min (offset);
      c->add_link (*offset, id);
    }
    
    static void run_resolve_overflow_test (const char* name,
                                           hb_serialize_context_t& overflowing,
                                           hb_serialize_context_t& expected,
                                           unsigned num_iterations = 0)
    {
      printf (">>> Testing overflowing resolution for %s\n",
              name);
    
      graph_t graph (overflowing.object_graph ());
    
      unsigned buffer_size = overflowing.end - overflowing.start;
      void* out_buffer = malloc (buffer_size);
      hb_serialize_context_t out (out_buffer, buffer_size);
    
      assert (overflowing.offset_overflow ());
      hb_resolve_overflows (overflowing.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), &out, num_iterations);
      assert (!out.offset_overflow ());
      hb_bytes_t result = out.copy_bytes ();
    
      assert (!expected.offset_overflow ());
      hb_bytes_t expected_result = expected.copy_bytes ();
    
      assert (result.length == expected_result.length);
      for (unsigned i = 0; i < expected_result.length; i++)
      {
        assert (result[i] == expected_result[i]);
      }
    
      result.fini ();
      expected_result.fini ();
      free (out_buffer);
    }
    
    static void add_virtual_offset (unsigned id,
                                    hb_serialize_context_t* c)
    {
      c->add_virtual_link (id);
    }
    
    static void
    populate_serializer_simple (hb_serialize_context_t* c)
    {
      c->start_serialize<char> ();
    
      unsigned obj_1 = add_object ("ghi", 3, c);
      unsigned obj_2 = add_object ("def", 3, c);
    
      start_object ("abc", 3, c);
      add_offset (obj_2, c);
      add_offset (obj_1, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_with_overflow (hb_serialize_context_t* c)
    {
      std::string large_string(50000, 'a');
      c->start_serialize<char> ();
    
      unsigned obj_1 = add_object (large_string.c_str(), 10000, c);
      unsigned obj_2 = add_object (large_string.c_str(), 20000, c);
      unsigned obj_3 = add_object (large_string.c_str(), 50000, c);
    
      start_object ("abc", 3, c);
      add_offset (obj_3, c);
      add_offset (obj_2, c);
      add_offset (obj_1, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_with_dedup_overflow (hb_serialize_context_t* c)
    {
      std::string large_string(70000, 'a');
      c->start_serialize<char> ();
    
      unsigned obj_1 = add_object ("def", 3, c);
    
      start_object (large_string.c_str(), 60000, c);
      add_offset (obj_1, c);
      unsigned obj_2 = c->pop_pack (false);
    
      start_object (large_string.c_str(), 10000, c);
      add_offset (obj_2, c);
      add_offset (obj_1, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_with_isolation_overflow (hb_serialize_context_t* c)
    {
      std::string large_string(70000, 'a');
      c->start_serialize<char> ();
    
      unsigned obj_4 = add_object ("4", 1, c);
    
      start_object (large_string.c_str(), 60000, c);
      add_offset (obj_4, c);
      unsigned obj_3 = c->pop_pack (false);
    
      start_object (large_string.c_str(), 10000, c);
      add_offset (obj_4, c);
      unsigned obj_2 = c->pop_pack (false);
    
      start_object ("1", 1, c);
      add_wide_offset (obj_3, c);
      add_offset (obj_2, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_with_isolation_overflow_complex (hb_serialize_context_t* c)
    {
      std::string large_string(70000, 'a');
      c->start_serialize<char> ();
    
      unsigned obj_f = add_object ("f", 1, c);
    
      start_object ("e", 1, c);
      add_offset (obj_f, c);
      unsigned obj_e = c->pop_pack (false);
    
      start_object ("c", 1, c);
      add_offset (obj_e, c);
      unsigned obj_c = c->pop_pack (false);
    
      start_object ("d", 1, c);
      add_offset (obj_e, c);
      unsigned obj_d = c->pop_pack (false);
    
      start_object (large_string.c_str(), 60000, c);
      add_offset (obj_d, c);
      unsigned obj_h = c->pop_pack (false);
    
      start_object (large_string.c_str(), 60000, c);
      add_offset (obj_c, c);
      add_offset (obj_h, c);
      unsigned obj_b = c->pop_pack (false);
    
      start_object (large_string.c_str(), 10000, c);
      add_offset (obj_d, c);
      unsigned obj_g = c->pop_pack (false);
    
      start_object (large_string.c_str(), 11000, c);
      add_offset (obj_d, c);
      unsigned obj_i = c->pop_pack (false);
    
      start_object ("a", 1, c);
      add_wide_offset (obj_b, c);
      add_offset (obj_g, c);
      add_offset (obj_i, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_with_isolation_overflow_complex_expected (hb_serialize_context_t* c)
    {
      std::string large_string(70000, 'a');
      c->start_serialize<char> ();
    
    
      // space 1
    
      unsigned obj_f_prime = add_object ("f", 1, c);
    
      start_object ("e", 1, c);
      add_offset (obj_f_prime, c);
      unsigned obj_e_prime = c->pop_pack (false);
    
      start_object ("d", 1, c);
      add_offset (obj_e_prime, c);
      unsigned obj_d_prime = c->pop_pack (false);
    
      start_object (large_string.c_str(), 60000, c);
      add_offset (obj_d_prime, c);
      unsigned obj_h = c->pop_pack (false);
    
      start_object ("c", 1, c);
      add_offset (obj_e_prime, c);
      unsigned obj_c = c->pop_pack (false);
    
      start_object (large_string.c_str(), 60000, c);
      add_offset (obj_c, c);
      add_offset (obj_h, c);
      unsigned obj_b = c->pop_pack (false);
    
      // space 0
    
      unsigned obj_f = add_object ("f", 1, c);
    
      start_object ("e", 1, c);
      add_offset (obj_f, c);
      unsigned obj_e = c->pop_pack (false);
    
    
      start_object ("d", 1, c);
      add_offset (obj_e, c);
      unsigned obj_d = c->pop_pack (false);
    
      start_object (large_string.c_str(), 11000, c);
      add_offset (obj_d, c);
      unsigned obj_i = c->pop_pack (false);
    
      start_object (large_string.c_str(), 10000, c);
      add_offset (obj_d, c);
      unsigned obj_g = c->pop_pack (false);
    
      start_object ("a", 1, c);
      add_wide_offset (obj_b, c);
      add_offset (obj_g, c);
      add_offset (obj_i, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_with_isolation_overflow_spaces (hb_serialize_context_t* c)
    {
      std::string large_string(70000, 'a');
      c->start_serialize<char> ();
    
      unsigned obj_d = add_object ("f", 1, c);
      unsigned obj_e = add_object ("f", 1, c);
    
      start_object (large_string.c_str(), 60000, c);
      add_offset (obj_d, c);
      unsigned obj_b = c->pop_pack ();
    
      start_object (large_string.c_str(), 60000, c);
      add_offset (obj_e, c);
      unsigned obj_c = c->pop_pack ();
    
    
      start_object ("a", 1, c);
      add_wide_offset (obj_b, c);
      add_wide_offset (obj_c, c);
      c->pop_pack ();
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_spaces (hb_serialize_context_t* c, bool with_overflow)
    {
      std::string large_string(70000, 'a');
      c->start_serialize<char> ();
    
      unsigned obj_i;
    
      if (with_overflow)
        obj_i = add_object ("i", 1, c);
    
      // Space 2
      unsigned obj_h = add_object ("h", 1, c);
    
      start_object (large_string.c_str(), 30000, c);
      add_offset (obj_h, c);
      unsigned obj_e = c->pop_pack (false);
    
      start_object ("b", 1, c);
      add_offset (obj_e, c);
      unsigned obj_b = c->pop_pack (false);
    
      // Space 1
      if (!with_overflow)
        obj_i = add_object ("i", 1, c);
    
      start_object (large_string.c_str(), 30000, c);
      add_offset (obj_i, c);
      unsigned obj_g = c->pop_pack (false);
    
      start_object (large_string.c_str(), 30000, c);
      add_offset (obj_i, c);
      unsigned obj_f = c->pop_pack (false);
    
      start_object ("d", 1, c);
      add_offset (obj_g, c);
      unsigned obj_d = c->pop_pack (false);
    
      start_object ("c", 1, c);
      add_offset (obj_f, c);
      unsigned obj_c = c->pop_pack (false);
    
      start_object ("a", 1, c);
      add_wide_offset (obj_b, c);
      add_wide_offset (obj_c, c);
      add_wide_offset (obj_d, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_spaces_16bit_connection (hb_serialize_context_t* c)
    {
      std::string large_string(70000, 'a');
      c->start_serialize<char> ();
    
      unsigned obj_g = add_object ("g", 1, c);
      unsigned obj_h = add_object ("h", 1, c);
    
      start_object (large_string.c_str (), 40000, c);
      add_offset (obj_g, c);
      unsigned obj_e = c->pop_pack (false);
    
      start_object (large_string.c_str (), 40000, c);
      add_offset (obj_h, c);
      unsigned obj_f = c->pop_pack (false);
    
      start_object ("c", 1, c);
      add_offset (obj_e, c);
      unsigned obj_c = c->pop_pack (false);
    
      start_object ("d", 1, c);
      add_offset (obj_f, c);
      unsigned obj_d = c->pop_pack (false);
    
      start_object ("b", 1, c);
      add_offset (obj_e, c);
      add_offset (obj_h, c);
      unsigned obj_b = c->pop_pack (false);
    
      start_object ("a", 1, c);
      add_offset (obj_b, c);
      add_wide_offset (obj_c, c);
      add_wide_offset (obj_d, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_spaces_16bit_connection_expected (hb_serialize_context_t* c)
    {
      std::string large_string(70000, 'a');
      c->start_serialize<char> ();
    
      unsigned obj_g_prime = add_object ("g", 1, c);
    
      start_object (large_string.c_str (), 40000, c);
      add_offset (obj_g_prime, c);
      unsigned obj_e_prime = c->pop_pack (false);
    
      start_object ("c", 1, c);
      add_offset (obj_e_prime, c);
      unsigned obj_c = c->pop_pack (false);
    
      unsigned obj_h_prime = add_object ("h", 1, c);
    
      start_object (large_string.c_str (), 40000, c);
      add_offset (obj_h_prime, c);
      unsigned obj_f = c->pop_pack (false);
    
      start_object ("d", 1, c);
      add_offset (obj_f, c);
      unsigned obj_d = c->pop_pack (false);
    
      unsigned obj_g = add_object ("g", 1, c);
    
      start_object (large_string.c_str (), 40000, c);
      add_offset (obj_g, c);
      unsigned obj_e = c->pop_pack (false);
    
      unsigned obj_h = add_object ("h", 1, c);
    
      start_object ("b", 1, c);
      add_offset (obj_e, c);
      add_offset (obj_h, c);
      unsigned obj_b = c->pop_pack (false);
    
      start_object ("a", 1, c);
      add_offset (obj_b, c);
      add_wide_offset (obj_c, c);
      add_wide_offset (obj_d, c);
      c->pop_pack (false);
    
      c->end_serialize ();
    }
    
    static void
    populate_serializer_short_and_wide_subgraph_root (hb_serialize_context_t* c)
    {
      std::string large_string(70000, 'a');
      c->start_serialize<char> ();
    
      unsigned obj_e = add_object ("e", 1, c);
    
      start_object (large_string.c_str (), 40000, c);
      add_offset (obj_e, c);
      unsigned obj_c = c->pop_pack (false);
    
      start_object (large_string.c_str (), 40000, c);
      add_offset (obj_c, c);
      unsigned obj_d = c->pop_pack (false);
    
      start_object ("b", 1, c);
      add_offset (obj_c, c);
      add_offset (obj_e, c);
      unsigned obj_b = c->pop_pack (false);
    
      start_object ("a", 1, c);
      add_offset (obj_b, c);
      add_wide_offset (obj_c, c);
      add_wide_offset (obj_d, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_short_and_wide_subgraph_root_expected (hb_serialize_context_t* c)
    {
      std::string large_string(70000, 'a');
      c->start_serialize<char> ();
    
      unsigned obj_e_prime = add_object ("e", 1, c);
    
      start_object (large_string.c_str (), 40000, c);
      add_offset (obj_e_prime, c);
      unsigned obj_c_prime = c->pop_pack (false);
    
      start_object (large_string.c_str (), 40000, c);
      add_offset (obj_c_prime, c);
      unsigned obj_d = c->pop_pack (false);
    
      unsigned obj_e = add_object ("e", 1, c);
    
      start_object (large_string.c_str (), 40000, c);
      add_offset (obj_e, c);
      unsigned obj_c = c->pop_pack (false);
    
    
      start_object ("b", 1, c);
      add_offset (obj_c, c);
      add_offset (obj_e, c);
      unsigned obj_b = c->pop_pack (false);
    
      start_object ("a", 1, c);
      add_offset (obj_b, c);
      add_wide_offset (obj_c_prime, c);
      add_wide_offset (obj_d, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_with_split_spaces (hb_serialize_context_t* c)
    {
      // Overflow needs to be resolved by splitting the single space
      std::string large_string(70000, 'a');
      c->start_serialize<char> ();
    
      unsigned obj_f = add_object ("f", 1, c);
    
      start_object (large_string.c_str(), 40000, c);
      add_offset (obj_f, c);
      unsigned obj_d = c->pop_pack (false);
    
      start_object (large_string.c_str(), 40000, c);
      add_offset (obj_f, c);
      unsigned obj_e = c->pop_pack (false);
    
      start_object ("b", 1, c);
      add_offset (obj_d, c);
      unsigned obj_b = c->pop_pack (false);
    
      start_object ("c", 1, c);
      add_offset (obj_e, c);
      unsigned obj_c = c->pop_pack (false);
    
      start_object ("a", 1, c);
      add_wide_offset (obj_b, c);
      add_wide_offset (obj_c, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_with_split_spaces_2 (hb_serialize_context_t* c)
    {
      // Overflow needs to be resolved by splitting the single space
      std::string large_string(70000, 'a');
      c->start_serialize<char> ();
    
      unsigned obj_f = add_object ("f", 1, c);
    
      start_object (large_string.c_str(), 40000, c);
      add_offset (obj_f, c);
      unsigned obj_d = c->pop_pack (false);
    
      start_object (large_string.c_str(), 40000, c);
      add_offset (obj_f, c);
      unsigned obj_e = c->pop_pack (false);
    
      start_object ("b", 1, c);
      add_offset (obj_d, c);
      unsigned obj_b = c->pop_pack (false);
    
      start_object ("c", 1, c);
      add_offset (obj_e, c);
      unsigned obj_c = c->pop_pack (false);
    
      start_object ("a", 1, c);
      add_offset (obj_b, c);
      add_wide_offset (obj_b, c);
      add_wide_offset (obj_c, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_with_split_spaces_expected (hb_serialize_context_t* c)
    {
      // Overflow needs to be resolved by splitting the single space
    
      std::string large_string(70000, 'a');
      c->start_serialize<char> ();
    
      unsigned obj_f_prime = add_object ("f", 1, c);
    
      start_object (large_string.c_str(), 40000, c);
      add_offset (obj_f_prime, c);
      unsigned obj_d = c->pop_pack (false);
    
      start_object ("b", 1, c);
      add_offset (obj_d, c);
      unsigned obj_b = c->pop_pack (false);
    
      unsigned obj_f = add_object ("f", 1, c);
    
      start_object (large_string.c_str(), 40000, c);
      add_offset (obj_f, c);
      unsigned obj_e = c->pop_pack (false);
    
      start_object ("c", 1, c);
      add_offset (obj_e, c);
      unsigned obj_c = c->pop_pack (false);
    
      start_object ("a", 1, c);
      add_wide_offset (obj_b, c);
      add_wide_offset (obj_c, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_with_split_spaces_expected_2 (hb_serialize_context_t* c)
    {
      // Overflow needs to be resolved by splitting the single space
    
      std::string large_string(70000, 'a');
      c->start_serialize<char> ();
    
      // Space 2
    
      unsigned obj_f_double_prime = add_object ("f", 1, c);
    
      start_object (large_string.c_str(), 40000, c);
      add_offset (obj_f_double_prime, c);
      unsigned obj_d_prime = c->pop_pack (false);
    
      start_object ("b", 1, c);
      add_offset (obj_d_prime, c);
      unsigned obj_b_prime = c->pop_pack (false);
    
      // Space 1
    
      unsigned obj_f_prime = add_object ("f", 1, c);
    
      start_object (large_string.c_str(), 40000, c);
      add_offset (obj_f_prime, c);
      unsigned obj_e = c->pop_pack (false);
    
      start_object ("c", 1, c);
      add_offset (obj_e, c);
      unsigned obj_c = c->pop_pack (false);
    
      // Space 0
    
      unsigned obj_f = add_object ("f", 1, c);
    
      start_object (large_string.c_str(), 40000, c);
      add_offset (obj_f, c);
      unsigned obj_d = c->pop_pack (false);
    
      start_object ("b", 1, c);
      add_offset (obj_d, c);
      unsigned obj_b = c->pop_pack (false);
    
      // Root
      start_object ("a", 1, c);
      add_offset (obj_b, c);
      add_wide_offset (obj_b_prime, c);
      add_wide_offset (obj_c, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_complex_1 (hb_serialize_context_t* c)
    {
      c->start_serialize<char> ();
    
      unsigned obj_4 = add_object ("jkl", 3, c);
      unsigned obj_3 = add_object ("ghi", 3, c);
    
      start_object ("def", 3, c);
      add_offset (obj_3, c);
      unsigned obj_2 = c->pop_pack (false);
    
      start_object ("abc", 3, c);
      add_offset (obj_2, c);
      add_offset (obj_4, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_complex_2 (hb_serialize_context_t* c)
    {
      c->start_serialize<char> ();
    
      unsigned obj_5 = add_object ("mn", 2, c);
    
      unsigned obj_4 = add_object ("jkl", 3, c);
    
      start_object ("ghi", 3, c);
      add_offset (obj_4, c);
      unsigned obj_3 = c->pop_pack (false);
    
      start_object ("def", 3, c);
      add_offset (obj_3, c);
      unsigned obj_2 = c->pop_pack (false);
    
      start_object ("abc", 3, c);
      add_offset (obj_2, c);
      add_offset (obj_4, c);
      add_offset (obj_5, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_complex_3 (hb_serialize_context_t* c)
    {
      c->start_serialize<char> ();
    
      unsigned obj_6 = add_object ("opqrst", 6, c);
    
      unsigned obj_5 = add_object ("mn", 2, c);
    
      start_object ("jkl", 3, c);
      add_offset (obj_6, c);
      unsigned obj_4 = c->pop_pack (false);
    
      start_object ("ghi", 3, c);
      add_offset (obj_4, c);
      unsigned obj_3 = c->pop_pack (false);
    
      start_object ("def", 3, c);
      add_offset (obj_3, c);
      unsigned obj_2 = c->pop_pack (false);
    
      start_object ("abc", 3, c);
      add_offset (obj_2, c);
      add_offset (obj_4, c);
      add_offset (obj_5, c);
      c->pop_pack (false);
    
      c->end_serialize();
    }
    
    static void
    populate_serializer_virtual_link (hb_serialize_context_t* c)
    {
      c->start_serialize<char> ();
    
      unsigned obj_d = add_object ("d", 1, c);
    
      start_object ("b", 1, c);
      add_offset (obj_d, c);
      unsigned obj_b = c->pop_pack ();
    
      start_object ("e", 1, c);
      add_virtual_offset (obj_b, c);
      unsigned obj_e = c->pop_pack();
    
      start_object ("c", 1, c);
      add_offset (obj_e, c);
      unsigned obj_c = c->pop_pack ();
    
      start_object ("a", 1, c);
      add_offset (obj_b, c);
      add_offset (obj_c, c);
      c->pop_pack ();
    
      c->end_serialize();
    }
    
    static void test_sort_kahn_1 ()
    {
      size_t buffer_size = 100;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_complex_1 (&c);
    
      graph_t graph (c.object_graph ());
      graph.sort_kahn ();
    
      assert(strncmp (graph.object (3).head, "abc", 3) == 0);
      assert(graph.object (3).links.length == 2);
      assert(graph.object (3).links[0].objidx == 2);
      assert(graph.object (3).links[1].objidx == 1);
    
      assert(strncmp (graph.object (2).head, "def", 3) == 0);
      assert(graph.object (2).links.length == 1);
      assert(graph.object (2).links[0].objidx == 0);
    
      assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
      assert(graph.object (1).links.length == 0);
    
      assert(strncmp (graph.object (0).head, "ghi", 3) == 0);
      assert(graph.object (0).links.length == 0);
    
      free (buffer);
    }
    
    static void test_sort_kahn_2 ()
    {
      size_t buffer_size = 100;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_complex_2 (&c);
    
      graph_t graph (c.object_graph ());
      graph.sort_kahn ();
    
    
      assert(strncmp (graph.object (4).head, "abc", 3) == 0);
      assert(graph.object (4).links.length == 3);
      assert(graph.object (4).links[0].objidx == 3);
        assert(graph.object (4).links[1].objidx == 0);
      assert(graph.object (4).links[2].objidx == 2);
    
      assert(strncmp (graph.object (3).head, "def", 3) == 0);
      assert(graph.object (3).links.length == 1);
      assert(graph.object (3).links[0].objidx == 1);
    
      assert(strncmp (graph.object (2).head, "mn", 2) == 0);
      assert(graph.object (2).links.length == 0);
    
      assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
      assert(graph.object (1).links.length == 1);
      assert(graph.object (1).links[0].objidx == 0);
    
      assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
      assert(graph.object (0).links.length == 0);
    
      free (buffer);
    }
    
    static void test_sort_shortest ()
    {
      size_t buffer_size = 100;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_complex_2 (&c);
    
      graph_t graph (c.object_graph ());
      graph.sort_shortest_distance ();
    
      assert(strncmp (graph.object (4).head, "abc", 3) == 0);
      assert(graph.object (4).links.length == 3);
      assert(graph.object (4).links[0].objidx == 2);
      assert(graph.object (4).links[1].objidx == 0);
      assert(graph.object (4).links[2].objidx == 3);
    
      assert(strncmp (graph.object (3).head, "mn", 2) == 0);
      assert(graph.object (3).links.length == 0);
    
      assert(strncmp (graph.object (2).head, "def", 3) == 0);
      assert(graph.object (2).links.length == 1);
      assert(graph.object (2).links[0].objidx == 1);
    
      assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
      assert(graph.object (1).links.length == 1);
      assert(graph.object (1).links[0].objidx == 0);
    
      assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
      assert(graph.object (0).links.length == 0);
    
      free (buffer);
    }
    
    static void test_duplicate_leaf ()
    {
      size_t buffer_size = 100;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_complex_2 (&c);
    
      graph_t graph (c.object_graph ());
      graph.duplicate (4, 1);
    
      assert(strncmp (graph.object (5).head, "abc", 3) == 0);
      assert(graph.object (5).links.length == 3);
      assert(graph.object (5).links[0].objidx == 3);
      assert(graph.object (5).links[1].objidx == 4);
      assert(graph.object (5).links[2].objidx == 0);
    
      assert(strncmp (graph.object (4).head, "jkl", 3) == 0);
      assert(graph.object (4).links.length == 0);
    
      assert(strncmp (graph.object (3).head, "def", 3) == 0);
      assert(graph.object (3).links.length == 1);
      assert(graph.object (3).links[0].objidx == 2);
    
      assert(strncmp (graph.object (2).head, "ghi", 3) == 0);
      assert(graph.object (2).links.length == 1);
      assert(graph.object (2).links[0].objidx == 1);
    
      assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
      assert(graph.object (1).links.length == 0);
    
      assert(strncmp (graph.object (0).head, "mn", 2) == 0);
      assert(graph.object (0).links.length == 0);
    
      free (buffer);
    }
    
    static void test_duplicate_interior ()
    {
      size_t buffer_size = 100;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_complex_3 (&c);
    
      graph_t graph (c.object_graph ());
      graph.duplicate (3, 2);
    
      assert(strncmp (graph.object (6).head, "abc", 3) == 0);
      assert(graph.object (6).links.length == 3);
      assert(graph.object (6).links[0].objidx == 4);
      assert(graph.object (6).links[1].objidx == 2);
      assert(graph.object (6).links[2].objidx == 1);
    
      assert(strncmp (graph.object (5).head, "jkl", 3) == 0);
      assert(graph.object (5).links.length == 1);
      assert(graph.object (5).links[0].objidx == 0);
    
      assert(strncmp (graph.object (4).head, "def", 3) == 0);
      assert(graph.object (4).links.length == 1);
      assert(graph.object (4).links[0].objidx == 3);
    
      assert(strncmp (graph.object (3).head, "ghi", 3) == 0);
      assert(graph.object (3).links.length == 1);
      assert(graph.object (3).links[0].objidx == 5);
    
      assert(strncmp (graph.object (2).head, "jkl", 3) == 0);
      assert(graph.object (2).links.length == 1);
      assert(graph.object (2).links[0].objidx == 0);
    
      assert(strncmp (graph.object (1).head, "mn", 2) == 0);
      assert(graph.object (1).links.length == 0);
    
      assert(strncmp (graph.object (0).head, "opqrst", 6) == 0);
      assert(graph.object (0).links.length == 0);
    
      free (buffer);
    }
    
    static void
    test_serialize ()
    {
      size_t buffer_size = 100;
      void* buffer_1 = malloc (buffer_size);
      hb_serialize_context_t c1 (buffer_1, buffer_size);
      populate_serializer_simple (&c1);
      hb_bytes_t expected = c1.copy_bytes ();
    
      void* buffer_2 = malloc (buffer_size);
      hb_serialize_context_t c2 (buffer_2, buffer_size);
    
      graph_t graph (c1.object_graph ());
      graph.serialize (&c2);
      hb_bytes_t actual = c2.copy_bytes ();
    
      assert (actual == expected);
    
      actual.fini ();
      expected.fini ();
      free (buffer_1);
      free (buffer_2);
    }
    
    static void test_will_overflow_1 ()
    {
      size_t buffer_size = 100;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_complex_2 (&c);
      graph_t graph (c.object_graph ());
    
      assert (!graph.will_overflow (nullptr));
    
      free (buffer);
    }
    
    static void test_will_overflow_2 ()
    {
      size_t buffer_size = 160000;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_with_overflow (&c);
      graph_t graph (c.object_graph ());
    
      assert (graph.will_overflow (nullptr));
    
      free (buffer);
    }
    
    static void test_will_overflow_3 ()
    {
      size_t buffer_size = 160000;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_with_dedup_overflow (&c);
      graph_t graph (c.object_graph ());
    
      assert (graph.will_overflow (nullptr));
    
      free (buffer);
    }
    
    static void test_resolve_overflows_via_sort ()
    {
      size_t buffer_size = 160000;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_with_overflow (&c);
      graph_t graph (c.object_graph ());
    
      void* out_buffer = malloc (buffer_size);
      hb_serialize_context_t out (out_buffer, buffer_size);
    
      hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, &out);
      assert (!out.offset_overflow ());
      hb_bytes_t result = out.copy_bytes ();
      assert (result.length == (80000 + 3 + 3 * 2));
    
      result.fini ();
      free (buffer);
      free (out_buffer);
    }
    
    static void test_resolve_overflows_via_duplication ()
    {
      size_t buffer_size = 160000;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_with_dedup_overflow (&c);
      graph_t graph (c.object_graph ());
    
      void* out_buffer = malloc (buffer_size);
      hb_serialize_context_t out (out_buffer, buffer_size);
    
      hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, &out);
      assert (!out.offset_overflow ());
      hb_bytes_t result = out.copy_bytes ();
      assert (result.length == (10000 + 2 * 2 + 60000 + 2 + 3 * 2));
    
      result.fini ();
      free (buffer);
      free (out_buffer);
    }
    
    static void test_resolve_overflows_via_space_assignment ()
    {
      size_t buffer_size = 160000;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_spaces (&c, true);
    
      void* expected_buffer = malloc (buffer_size);
      hb_serialize_context_t e (expected_buffer, buffer_size);
      populate_serializer_spaces (&e, false);
    
      run_resolve_overflow_test ("test_resolve_overflows_via_space_assignment",
                                 c,
                                 e);
    
      free (buffer);
      free (expected_buffer);
    }
    
    static void test_resolve_overflows_via_isolation ()
    {
      size_t buffer_size = 160000;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_with_isolation_overflow (&c);
      graph_t graph (c.object_graph ());
    
      void* out_buffer = malloc (buffer_size);
      hb_serialize_context_t out (out_buffer, buffer_size);
    
      assert (c.offset_overflow ());
      hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), &out, 0);
      assert (!out.offset_overflow ());
      hb_bytes_t result = out.copy_bytes ();
      assert (result.length == (1 + 10000 + 60000 + 1 + 1
                                + 4 + 3 * 2));
    
      result.fini ();
      free (buffer);
      free (out_buffer);
    }
    
    static void test_resolve_overflows_via_isolation_with_recursive_duplication ()
    {
      size_t buffer_size = 160000;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_with_isolation_overflow_complex (&c);
    
      void* expected_buffer = malloc (buffer_size);
      hb_serialize_context_t e (expected_buffer, buffer_size);
      populate_serializer_with_isolation_overflow_complex_expected (&e);
    
      run_resolve_overflow_test ("test_resolve_overflows_via_isolation_with_recursive_duplication",
                                 c,
                                 e);
      free (buffer);
      free (expected_buffer);
    }
    
    static void test_resolve_overflows_via_isolating_16bit_space ()
    {
      size_t buffer_size = 160000;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_spaces_16bit_connection (&c);
    
      void* expected_buffer = malloc (buffer_size);
      hb_serialize_context_t e (expected_buffer, buffer_size);
      populate_serializer_spaces_16bit_connection_expected (&e);
    
      run_resolve_overflow_test ("test_resolve_overflows_via_isolating_16bit_space",
                                 c,
                                 e);
    
      free (buffer);
      free (expected_buffer);
    }
    
    static void test_resolve_overflows_via_isolating_16bit_space_2 ()
    {
      size_t buffer_size = 160000;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_short_and_wide_subgraph_root (&c);
    
      void* expected_buffer = malloc (buffer_size);
      hb_serialize_context_t e (expected_buffer, buffer_size);
      populate_serializer_short_and_wide_subgraph_root_expected (&e);
    
      run_resolve_overflow_test ("test_resolve_overflows_via_isolating_16bit_space_2",
                                 c,
                                 e);
    
      free (buffer);
      free (expected_buffer);
    }
    
    static void test_resolve_overflows_via_isolation_spaces ()
    {
      size_t buffer_size = 160000;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_with_isolation_overflow_spaces (&c);
      graph_t graph (c.object_graph ());
    
      void* out_buffer = malloc (buffer_size);
      hb_serialize_context_t out (out_buffer, buffer_size);
    
      assert (c.offset_overflow ());
      hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), &out, 0);
      assert (!out.offset_overflow ());
      hb_bytes_t result = out.copy_bytes ();
    
      unsigned expected_length = 3 + 2 * 60000; // objects
      expected_length += 2 * 4 + 2 * 2; // links
      assert (result.length == expected_length);
    
      result.fini ();
      free (buffer);
      free (out_buffer);
    }
    
    static void test_resolve_overflows_via_splitting_spaces ()
    {
      size_t buffer_size = 160000;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_with_split_spaces (&c);
    
      void* expected_buffer = malloc (buffer_size);
      hb_serialize_context_t e (expected_buffer, buffer_size);
      populate_serializer_with_split_spaces_expected (&e);
    
      run_resolve_overflow_test ("test_resolve_overflows_via_splitting_spaces",
                                 c,
                                 e,
                                 1);
    
      free (buffer);
      free (expected_buffer);
    
    }
    
    static void test_resolve_overflows_via_splitting_spaces_2 ()
    {
      size_t buffer_size = 160000;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_with_split_spaces_2 (&c);
    
      void* expected_buffer = malloc (buffer_size);
      hb_serialize_context_t e (expected_buffer, buffer_size);
      populate_serializer_with_split_spaces_expected_2 (&e);
    
      run_resolve_overflow_test ("test_resolve_overflows_via_splitting_spaces_2",
                                 c,
                                 e,
                                 1);
      free (buffer);
      free (expected_buffer);
    }
    
    static void test_virtual_link ()
    {
      size_t buffer_size = 100;
      void* buffer = malloc (buffer_size);
      hb_serialize_context_t c (buffer, buffer_size);
      populate_serializer_virtual_link (&c);
    
      void* out_buffer = malloc (buffer_size);
      hb_serialize_context_t out (out_buffer, buffer_size);
    
      hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, &out);
      assert (!out.offset_overflow ());
    
      hb_bytes_t result = out.copy_bytes ();
      assert (result.length == 5 + 4 * 2);
      assert (result[0]  == 'a');
      assert (result[5]  == 'c');
      assert (result[8]  == 'e');
      assert (result[9]  == 'b');
      assert (result[12] == 'd');
    
      result.fini ();
      free (buffer);
      free (out_buffer);
    }
    
    // TODO(garretrieger): update will_overflow tests to check the overflows array.
    // TODO(garretrieger): add tests for priority raising.
    
    int
    main (int argc, char **argv)
    {
      test_serialize ();
      test_sort_kahn_1 ();
      test_sort_kahn_2 ();
      test_sort_shortest ();
      test_will_overflow_1 ();
      test_will_overflow_2 ();
      test_will_overflow_3 ();
      test_resolve_overflows_via_sort ();
      test_resolve_overflows_via_duplication ();
      test_resolve_overflows_via_space_assignment ();
      test_resolve_overflows_via_isolation ();
      test_resolve_overflows_via_isolation_with_recursive_duplication ();
      test_resolve_overflows_via_isolation_spaces ();
      test_resolve_overflows_via_isolating_16bit_space ();
      test_resolve_overflows_via_isolating_16bit_space_2 ();
      test_resolve_overflows_via_splitting_spaces ();
      test_resolve_overflows_via_splitting_spaces_2 ();
      test_duplicate_leaf ();
      test_duplicate_interior ();
      test_virtual_link ();
    }