std::string loadScriptFromFile(const std::string& fileName) {
  #ifdef WITH_FBSYSTRACE
  FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_loadScriptFromFile",
    "fileName", fileName);
  #endif
  std::ifstream jsfile(fileName);
  if (jsfile) {
    std::string output;
    jsfile.seekg(0, std::ios::end);
    output.reserve(jsfile.tellg());
    jsfile.seekg(0, std::ios::beg);
    output.assign(
      (std::istreambuf_iterator<char>(jsfile)),
      std::istreambuf_iterator<char>());
    return output;
  }

  FBLOGE("Unable to load script from file: %s", fileName.c_str());
  return "";
}
    // see http://duktape.org/guide.html#modules   
    static int js_module_search(duk_context* ctx)
    {       
        JSVM* vm = JSVM::GetJSVM(ctx);
        FileSystem* fs = vm->GetSubsystem<FileSystem>();
        ResourceCache* cache = vm->GetSubsystem<ResourceCache>();

        int top = duk_get_top(ctx);

        assert(top ==  4);

        String moduleID = duk_to_string(ctx, 0);

        if (top > 1)
        {
            // require function
            assert(duk_is_function(ctx, 1));
        }
        
        if (top > 2)
        {
            // exports
            assert(duk_is_object(ctx, 2));
        }

        if (top > 3)        
        {
            // module (module.id == a resolved absolute identifier for the module being loaded)
            assert(duk_is_object(ctx, 3));
        }

        String pathName, fileName, extension;
        SplitPath(moduleID, pathName, fileName, extension);
        String path = moduleID;

        // Do we really want this?  It is nice to not have to specify the Atomic path
        if (fileName.StartsWith("Atomic"))
        {
            path = "AtomicModules/" + path + ".js";
        }
        else
        {
            path += ".js";

            if (!cache->Exists(path))
            {
                const Vector<String>& searchPaths = vm->GetModuleSearchPaths();
                for (unsigned i = 0; i < searchPaths.Size(); i++)
                {
                    String search = searchPaths[i] + path;
                    if (cache->Exists(search))
                    {
                        path = search;
                        break;
                    }
                }
            }
        }

        if (cache->Exists(path))
        {
            SharedPtr<File> jsfile(cache->GetFile(path, false));
            vm->SetLastModuleSearchFile(jsfile->GetFullPath());
            String source;
            jsfile->ReadText(source);
            source.Append('\n');
            duk_push_string(ctx, source.CString());
            return 1;
        }
        else
        {
            // we're not a JS file, so check if we're a native module
            const Vector<String>& resourceDirs = cache->GetResourceDirs();

            for (unsigned i = 0; i < resourceDirs.Size(); i++)
            {

             String pluginLibrary;

             // TODO: proper platform folder detection
#ifdef ATOMIC_PLATFORM_WINDOWS              
              pluginLibrary = resourceDirs.At(i) + "Plugins/Windows/x64/" + moduleID + ".dll";
#elif ATOMIC_PLATFORM_OSX
             pluginLibrary = resourceDirs.At(i) + "Plugins/Mac/x64/lib" + moduleID + ".dylib";
#endif

               if (pluginLibrary.Length() && fs->FileExists(pluginLibrary))
                {
                    // let duktape know we loaded a native module
                    if (jsplugin_load(vm, pluginLibrary))
                    {
                        duk_push_undefined(ctx);
                        return 1;
                    }
                    else
                    {
                        duk_push_sprintf(ctx, "Failed loading native plugins: %s", pluginLibrary.CString());
                        duk_throw(ctx);
                    }
                }
            }

        }

        duk_push_sprintf(ctx, "Failed loading module: %s", path.CString());
        duk_throw(ctx);

    }
Exemple #3
0
void test_basic(char *filename)
{
    boro_t b;
    off_t r, i, i2, t, r2;
    boro_type_t fl;
    struct boro_node *n;
    struct boro_mr s1, s2, s3;
    FILE *f;
    int c;

    if (filename != NULL)
        unlink(filename);

    do_test("boro_open", boro_open(&b, filename));

    r = boro_begin_rw(&b);

    i = boro_new(&b, "key", boro_new_s(&b, "value"), BORO_STRING, 0, 0);

    n = boro_node(&b, i);
    do_test("n->n 1", n->n == 0);
    do_test("n->c 1", n->c == 1);

    r = boro_new(&b, "key2", boro_new_s(&b, "value2"), BORO_STRING, 0, i);

    n = boro_node(&b, i);
    do_test("n->n 2", n->n == 1);
    do_test("n->c 2", n->c == 1);

    n = boro_node(&b, r);
    do_test("n->n 2", n->n == 0);
    do_test("n->c 2", n->c == 2);

    boro_end_rw(&b, r);

    n = boro_node(&b, r);
    do_test("n->n 2", n->n == 1);
    do_test("n->c 2", n->c == 2);

    do_test("b->h->dq 1", b.h->dq == 0);

    r = boro_begin_rw(&b);
    i = boro_new(&b, "key3", boro_new_s(&b, "value3"), BORO_STRING, 0, 0);
    boro_end_rw(&b, i);

/*    if (b.f != -1)
        do_test("b->h->dq 2", b.h->dq == r);
*/
    boro_gc(&b);
    boro_gc(&b);
    boro_gc(&b);

    r = boro_begin_rw(&b);
    i = boro_new(&b, "key4", boro_new_s(&b, "value4"), BORO_STRING, 0, 0);
    boro_end_rw(&b, i);

    boro_gc(&b);

    r = boro_begin_rw(&b);
    r = boro_k_set(&b, r, "key5", boro_new_s(&b, "value5"), BORO_STRING);
    boro_end_rw(&b, r);

    r = boro_begin_rw(&b);
    do_test("boro_k_get before boro_k_delete", boro_k_get(&b, r, "key5") != 0);
    r = boro_k_delete(&b, r, "key5");
    do_test("boro_k_get after boro_k_delete", boro_k_get(&b, r, "key5") == 0);
    boro_end_rw(&b, r);

    boro_close(&b);

    if (filename != NULL)
        unlink(filename);

    do_test("boro_open", boro_open(&b, filename));

    r = boro_begin_rw(&b);
    r = boro_append(&b, r, boro_new_s(&b, "this"), BORO_STRING);
    r = boro_append(&b, r, boro_new_s(&b, "is"), BORO_STRING);
    r = boro_append(&b, r, boro_new_s(&b, "a"), BORO_STRING);
    r = boro_append(&b, r, boro_new_s(&b, "test"), BORO_STRING);
    boro_end_rw(&b, r);

    r = boro_begin_ro(&b);

    if (verbose) {
        boro_dump_as_tree(&b, r, 0, 0, 20);
        printf("\n");
        boro_dump_as_csv(&b, r);
    }

    i = boro_i_get(&b, r, 0);
    n = boro_node(&b, i);
    do_test("i_append & i_get 0", strcmp("this", boro_str(&b, n->v, n->t)) == 0);

    i = boro_i_get(&b, r, 1);
    n = boro_node(&b, i);
    do_test("i_append & i_get 1", strcmp("is", boro_str(&b, n->v, n->t)) == 0);

    i = boro_i_get(&b, r, 2);
    n = boro_node(&b, i);
    do_test("i_append & i_get 2", strcmp("a", boro_str(&b, n->v, n->t)) == 0);

    i = boro_i_get(&b, r, 3);
    n = boro_node(&b, i);
    do_test("i_append & i_get 3", strcmp("test", boro_str(&b, n->v, n->t)) == 0);

    i = boro_i_get(&b, r, 4);
    do_test("i_get 4", i == 0);

    boro_end_ro(&b, r);

    boro_close(&b);

    if (filename != NULL)
        unlink(filename);

    do_test("boro_open", boro_open(&b, filename));

    r = boro_begin_rw(&b);
    r = boro_sort(&b, r, boro_new_s(&b, "c"), BORO_STRING, 1);
    r = boro_sort(&b, r, boro_new_s(&b, "d"), BORO_STRING, 1);
    r = boro_sort(&b, r, boro_new_s(&b, "a"), BORO_STRING, 1);
    r = boro_sort(&b, r, boro_new_s(&b, "b"), BORO_STRING, 1);
    boro_end_rw(&b, r);

    r = boro_begin_ro(&b);

    if (verbose) {
        boro_dump_as_tree(&b, r, 0, 0, 20);
        printf("\n");
        boro_dump_as_csv(&b, r);
    }

    while (boro_gc(&b));

    if (verbose) {
        boro_dump_as_tree(&b, r, 0, 0, 20);
        printf("\n");
        boro_dump_as_csv(&b, r);
    }

    i = boro_i_get(&b, r, 0);
    n = boro_node(&b, i);
    do_test("i_sort & i_get 0", strcmp("a", boro_str(&b, n->v, n->t)) == 0);

    i = boro_i_get(&b, r, 1);
    n = boro_node(&b, i);
    do_test("i_sort & i_get 1", strcmp("b", boro_str(&b, n->v, n->t)) == 0);

    i = boro_i_get(&b, r, 2);
    n = boro_node(&b, i);
    do_test("i_sort & i_get 2", strcmp("c", boro_str(&b, n->v, n->t)) == 0);

    i = boro_i_get(&b, r, 3);
    n = boro_node(&b, i);
    do_test("i_sort & i_get 3", strcmp("d", boro_str(&b, n->v, n->t)) == 0);

    boro_end_ro(&b, r);

    if (verbose) {
        r = boro_begin_ro(&b);

        boro_mr_init(&s1, &b, boro_mr_json);
        s1.farg[0] = stdout;
        boro_mr(&s1, r, BORO_LIST);
        printf("\n");

        boro_mr_init(&s1, &b, boro_mr_slice);
        s1.iarg[0] = 1;
        s1.iarg[1] = 2;
        boro_mr_init(&s2, &b, boro_mr_json);
        s2.farg[0] = stdout;
        boro_mr_chain(&s1, &s2);
        boro_mr(&s1, r, BORO_LIST);
        printf("\n");

        boro_end_ro(&b, r);
    }

    r = boro_begin_ro(&b);

    boro_mr_init(&s1, &b, boro_mr_slice);
    s1.iarg[0] = 1;
    s1.iarg[1] = 2;
    boro_mr_init(&s2, &b, boro_mr_store);
    boro_mr_chain(&s1, &s2);
    boro_mr(&s1, r, BORO_LIST);

    t = s2.r;
    boro_ref(&b, t);
    i = boro_i_get(&b, t, 0);
    n = boro_node(&b, i);
    do_test("slice + store 1", n && strcmp(boro_str(&b, n->v, n->t), "b") == 0);
    i = boro_i_get(&b, t, 1);
    n = boro_node(&b, i);
    do_test("slice + store 2", n && strcmp(boro_str(&b, n->v, n->t), "c") == 0);
    boro_unref(&b, t);

    boro_end_ro(&b, r);

    while (boro_gc(&b));

    r = boro_begin_rw(&b);
    r = countries(&b);
    r = boro_k_set(&b, 0, "countries", r, BORO_DICT);
    boro_end_rw(&b, r);

    if (verbose) {
        r = boro_begin_ro(&b);
        boro_mr_init(&s1, &b, boro_mr_json);
        s1.farg[0] = stdout;
        boro_mr(&s1, r, BORO_DICT);
        printf("\n");
        boro_end_ro(&b, r);
    }

    r = boro_begin_ro(&b);

    i = boro_k_get(&b, r, "countries");
    n = boro_node(&b, i);
    t = n->v;

    boro_mr_init(&s1, &b, boro_mr_sort_by);
    s1.sarg[0] = "capital";
    boro_mr(&s1, t, 0);

    boro_ref(&b, s1.r);

    i = boro_i_get(&b, s1.r, 0);
    n = boro_node(&b, i);
    i = boro_k_get(&b, n->v, "capital");
    n = boro_node(&b, i);
    do_test("sort_by 1", n && strcmp(boro_str(&b, n->v, n->t), "Brussels") == 0);
    i = boro_i_get(&b, s1.r, 5);
    n = boro_node(&b, i);
    i = boro_k_get(&b, n->v, "capital");
    n = boro_node(&b, i);
    do_test("sort_by 2", n && strcmp(boro_str(&b, n->v, n->t), "Washington D.C.") == 0);

    if (verbose) {
        printf("sort_by capital:\n");
        print_tree(&b, s1.r, BORO_LIST);
    }

    boro_unref(&b, s1.r);

    i = boro_k_get(&b, r, "countries");
    n = boro_node(&b, i);
    t = n->v;

    boro_mr_init(&s1, &b, boro_mr_sort_by);
    s1.sarg[0] = "capital";
    boro_mr_init(&s2, &b, boro_mr_slice);
    s2.iarg[0] = 0;
    s2.iarg[1] = 0;
    boro_mr_init(&s3, &b, boro_mr_store);
    boro_mr_chain(&s1, &s2);
    boro_mr_chain(&s1, &s3);
    boro_mr(&s1, t, BORO_LIST);

    boro_ref(&b, s3.r);

    if (verbose) {
        printf("sort_by capital + slice(0, 0):\n");
        print_tree(&b, s3.r, BORO_LIST);
    }

    do_test("sort_by + slice + store", boro_count(&b, s3.r) == 1);
    boro_unref(&b, s3.r);

    boro_mr_init(&s1, &b, boro_mr_group_by);
    s1.sarg[0] = "continent";
    boro_mr(&s1, t, BORO_DICT);

    boro_ref(&b, s1.r);

    if (verbose) {
        printf("group_by:\n");
        print_tree(&b, s1.r, BORO_DICT);
    }

    i = boro_k_get(&b, s1.r, "Asia");
    n = boro_node(&b, i);
    do_test("group_by 1", n && boro_count(&b, n->v) == 1);
    i = boro_k_get(&b, s1.r, "America");
    n = boro_node(&b, i);
    do_test("group_by 2", n && boro_count(&b, n->v) == 1);
    i = boro_k_get(&b, s1.r, "Europe");
    n = boro_node(&b, i);
    do_test("group_by 3", n && boro_count(&b, n->v) == 4);

    boro_unref(&b, s1.r);

    while (boro_gc(&b));

    /* having */
    t = boro_k_set(&b, 0, "drives_on_the_right", 0, BORO_TRUE);
    boro_ref(&b, t);

    boro_mr_init(&s1, &b, boro_mr_having);
    s1.r = t;
    boro_mr_init(&s2, &b, boro_mr_store);
    boro_mr_chain(&s1, &s2);

    i = boro_k_get(&b, r, "countries");
    n = boro_node(&b, i);
    r2 = n->v;

    boro_mr(&s1, r2, 0);

    boro_ref(&b, s2.r);

    do_test("having 1", boro_k_get(&b, s2.r, "Spain") != 0);
    do_test("having 2", boro_k_get(&b, s2.r, "Belgium") != 0);
    do_test("having 3", boro_k_get(&b, s2.r, "France") != 0);
    do_test("having 4", boro_k_get(&b, s2.r, "United States of America") != 0);
    do_test("having 5", boro_k_get(&b, s2.r, "Japan") == 0);
    do_test("having 6", boro_k_get(&b, s2.r, "United Kingdom") == 0);

    if (verbose) {
        printf("having {drives_on_the_right: true}\n");
        print_tree(&b, s2.r, BORO_LIST);
    }

    boro_unref(&b, s2.r);

    boro_unref(&b, t);

    boro_end_ro(&b, r);

    while (boro_gc(&b));

    /* import */
    r = boro_begin_rw(&b);

    fl = 0;
    f = jsfile("[]");
    t = boro_import_json(&b, &fl, f);
    fclose(f);

    if (verbose)
        print_tree(&b, t, fl);

    do_test("import json 1 []", fl == BORO_LIST);

    fl = 0;
    f = jsfile("{}");
    t = boro_import_json(&b, &fl, f);
    fclose(f);

    if (verbose)
        print_tree(&b, t, fl);

    do_test("import json 2 {}", fl == BORO_DICT);

    fl = 0;
    f = jsfile("{\"a\":1}");
    t = boro_import_json(&b, &fl, f);
    fclose(f);

    if (verbose)
        print_tree(&b, t, fl);

    do_test("import json 3", fl == BORO_DICT);

    fl = 0;
    f = jsfile("{\"a\":\"c\",\"b\":[1,\"d\",3],\"e1\":{\"e1\":1.0,\"e2\":12.53}}");
    t = boro_import_json(&b, &fl, f);
    fclose(f);

    if (verbose)
        print_tree(&b, t, fl);

    do_test("import json 4", fl == BORO_DICT);

    fl = 0;
    f = jsfile("[\"a\",\"c\",\"b\",[1,\"d\",3],\"e1\",{\"e1\":1.0,\"e2\":12.53},null,true,false,12345.2345,\"no more\"]");
    t = boro_import_json(&b, &fl, f);
    fclose(f);

    if (verbose)
        print_tree(&b, t, fl);

    do_test("import json 5", fl == BORO_LIST);

    fl = 0;
    f = jsfile("[1");
    t = boro_import_json(&b, &fl, f);
    fclose(f);

    do_test("import json 6.1 (error)", fl == 0);

    fl = 0;
    f = jsfile("[1,");
    t = boro_import_json(&b, &fl, f);
    fclose(f);

    do_test("import json 6.2 (error)", fl == 0);

    fl = 0;
    f = jsfile("[1,2");
    t = boro_import_json(&b, &fl, f);
    fclose(f);

    do_test("import json 6.3 (error)", fl == 0);

    fl = 0;
    f = jsfile("[1,2,3");
    t = boro_import_json(&b, &fl, f);
    fclose(f);

    do_test("import json 6.4 (error)", fl == 0);

    fl = 0;
    f = jsfile("[1,true,2,false,[],{},null,4.567] garbage at the end");
    t = boro_import_json(&b, &fl, f);
    fclose(f);

    if (verbose)
        print_tree(&b, t, fl);

    do_test("import json 7", fl == BORO_LIST);

    fl = 0;
    f = jsfile("{\"a\":{\"b\":{\"c\":[1,2,3]}}}");
    t = boro_import_json(&b, &fl, f);
    fclose(f);

    if (verbose)
        print_tree(&b, t, fl);

    do_test("import json 8", fl == BORO_DICT);

    fl = 0;
    t = boro_import_json_s(&b, &fl,
        "{\"a\":\"c\",\"b\":[1,\"d\",3],\"e1\":{\"e1\":1.0,\"e2\":12.53}}");

    if (verbose)
        print_tree(&b, t, fl);

    do_test("import json_s 1", fl == BORO_DICT);

    while (boro_gc(&b));

    boro_end_rw(&b, r);

    while (boro_gc(&b));

    /* iterators */
    if (verbose)
        printf("Iterating countries:\n");

    struct boro_iter it;

    r = boro_begin_ro(&b);

    i = boro_k_get(&b, r, "countries");
    n = boro_node(&b, i);
    t = n->v;

    c = 0;
    boro_iter_init(&it, &b, t, 1);
    while ((n = boro_iter_next(&it))) {

        if (verbose)
            printf("%s\n", n->k);

        c++;
    }

    do_test("iterator 1", c == 6);

    if (verbose)
        printf("Iterator for France key/values (non-scalar values not shown):\n");

    i = boro_k_get(&b, t, "France");
    n = boro_node(&b, i);
    t = n->v;

    boro_iter_init(&it, &b, t, 1);
    while ((n = boro_iter_next(&it))) {

        if (verbose)
            printf("%s: %s\n", n->k, boro_str(&b, n->v, n->t));
    }

    i = boro_k_get(&b, r, "countries");
    n = boro_node(&b, i);
    t = n->v;

    if (verbose)
        printf("Inverse iterator for France key/values (non-scalar values not shown):\n");

    i = boro_k_get(&b, t, "France");
    n = boro_node(&b, i);
    t = n->v;

    boro_iter_init(&it, &b, t, -1);
    while ((n = boro_iter_next(&it))) {

        if (verbose)
            printf("%s: %s\n", n->k, boro_str(&b, n->v, n->t));
    }

    /* cmd_get */
    boro_mr_init(&s1, &b, boro_mr_crc32);

    if (verbose) {
        printf("boro_cmd_get countries/Spain:\n");
        boro_mr_init(&s2, &b, boro_mr_json);
        s2.farg[0] = stdout;
        boro_mr_chain(&s1, &s2);
    }

    fl = BORO_DICT;
    boro_cmd_get(&b, r, "countries/Spain", 0, &s1, &fl);

    if (verbose)
        printf("\ncrc32: %08x\n", s1.iarg[0]);

    do_test("boro_cmd_get countries/Spain", s1.iarg[0] == 0x5ec5188d);


    boro_mr_init(&s1, &b, boro_mr_crc32);

    if (verbose) {
        printf("boro_cmd_get countries/France:\n");
        boro_mr_init(&s2, &b, boro_mr_json);
        s2.farg[0] = stdout;
        boro_mr_chain(&s1, &s2);
    }

    fl = BORO_DICT;
    boro_cmd_get(&b, r, "countries/France", 0, &s1, &fl);

    if (verbose)
        printf("\ncrc32: %08x\n", s1.iarg[0]);

    do_test("boro_cmd_get countries/France", s1.iarg[0] == 0xc47c0a33);


    boro_mr_init(&s1, &b, boro_mr_crc32);

    t = boro_import_json_s(&b, &fl, "[[\"having\", {\"continent\":\"Asia\"}]]");
    boro_ref(&b, t);

    if (verbose) {
        printf("boro_cmd_get countries (having continent: Asia):\n");
        boro_mr_init(&s2, &b, boro_mr_json);
        s2.farg[0] = stdout;
        boro_mr_chain(&s1, &s2);
    }

    fl = BORO_DICT;

    boro_cmd_get(&b, r, "countries", t, &s1, &fl);

    if (verbose)
        printf("\ncrc32: %08x\n", s1.iarg[0]);

    do_test("boro_cmd_get countries (having continent: Asia)", s1.iarg[0] == 0xfe375820);

    boro_unref(&b, t);


    boro_mr_init(&s1, &b, boro_mr_crc32);

    t = boro_import_json_s(&b, &fl, "[[\"sort_by\", \"capital\"]]");
    boro_ref(&b, t);

    if (verbose) {
        printf("boro_cmd_get countries (sort_by capital):\n");
        boro_mr_init(&s2, &b, boro_mr_json);
        s2.farg[0] = stdout;
        boro_mr_chain(&s1, &s2);
    }

    fl = BORO_DICT;

    boro_cmd_get(&b, r, "countries", t, &s1, &fl);

    if (verbose)
        printf("\ncrc32: %08x\n", s1.iarg[0]);

    do_test("boro_cmd_get countries (sort_by capital)", s1.iarg[0] == 0xd01ce6b4);

    boro_unref(&b, t);


    boro_mr_init(&s1, &b, boro_mr_crc32);

    t = boro_import_json_s(&b, &fl, "[[\"sort_by\", \"population\"]]");
    boro_ref(&b, t);

    if (verbose) {
        printf("boro_cmd_get countries (sort_by population):\n");
        boro_mr_init(&s2, &b, boro_mr_json);
        s2.farg[0] = stdout;
        boro_mr_chain(&s1, &s2);
    }

    fl = BORO_DICT;

    boro_cmd_get(&b, r, "countries", t, &s1, &fl);

    if (verbose)
        printf("\ncrc32: %08x\n", s1.iarg[0]);

    do_test("boro_cmd_get countries (sort_by population)", s1.iarg[0] == 0x2e5af057);

    boro_unref(&b, t);


    i = boro_p_get(&b, r, BORO_DICT, "countries/Spain/capital");
    n = boro_node(&b, i);
    do_test("boro_p_get 1", strcmp(boro_str(&b, n->v, n->t), "Madrid") == 0);

    i = boro_p_get(&b, r, BORO_DICT, "countries/Spain/cities/0");
    n = boro_node(&b, i);
    do_test("boro_p_get 2", strcmp(boro_str(&b, n->v, n->t), "Barcelona") == 0);

    i = boro_p_get(&b, r, BORO_DICT, "countries/Spain/cities/2");
    n = boro_node(&b, i);
    do_test("boro_p_get 3", strcmp(boro_str(&b, n->v, n->t), "Sevilla") == 0);

    i = boro_p_get(&b, r, BORO_DICT, "countries/Spain/cities/3");
    do_test("boro_p_get 4", i == 0);


    boro_end_ro(&b, r);

    r = boro_begin_rw(&b);

    r = boro_p_set(&b, r, BORO_DICT, "countries/Portugal", 0, BORO_DICT);
    r = boro_p_set(&b, r, BORO_DICT, "countries/Portugal/capital", boro_new_s(&b, "Lisboa"), BORO_STRING);
    r = boro_p_set(&b, r, BORO_DICT, "countries/Portugal/cities", 0, BORO_LIST);
    r = boro_p_set(&b, r, BORO_DICT, "countries/Portugal/cities/", boro_new_s(&b, "Porto"), BORO_STRING);
    r = boro_p_set(&b, r, BORO_DICT, "countries/Portugal/cities/", boro_new_s(&b, "Coimbra"), BORO_STRING);
    r = boro_p_set(&b, r, BORO_DICT, "countries/Portugal/cities/", boro_new_s(&b, "Braga"), BORO_STRING);
    r = boro_p_set(&b, r, BORO_DICT, "countries/Portugal/drives_on_the_right", 0, BORO_TRUE);
    r = boro_p_set(&b, r, BORO_DICT, "countries/Portugal/continent", boro_new_s(&b, "Europe"), BORO_STRING);

    i = boro_p_get(&b, r, BORO_DICT, "countries/Portugal/capital");
    n = boro_node(&b, i);
    do_test("boro_p_set 1", strcmp(boro_str(&b, n->v, n->t), "Lisboa") == 0);

    boro_end_rw(&b, r);

    r = boro_begin_ro(&b);

    if (verbose) {
        printf("After adding Portugal:\n");
        print_tree(&b, r, BORO_DICT);
    }

    boro_end_ro(&b, r);

    if (verbose)
        printf("Creating a list and a dict...\n");

    r = boro_begin_rw(&b);
    char tmp[32];
    i = i2 = 0;
    for (c = 0; c < 10; c++) {
        sprintf(tmp, "%d", c);
        i = boro_append_p(&b, i, boro_new_s(&b, tmp), BORO_NUMBER);
        i2 = boro_k_set_p(&b, i2, tmp, boro_new_s(&b, tmp), BORO_NUMBER);
    }

    r = boro_p_set(&b, r, BORO_DICT, "list", i, BORO_LIST);
    r = boro_p_set(&b, r, BORO_DICT, "dict", i2, BORO_DICT);

    boro_end_rw(&b, r);

    if (verbose)
        printf("Done.\n");

    boro_close(&b);
}