<commit_before>#include <isl/set.h>
#include <isl/union_map.h>
#include <isl/union_set.h>
#include <isl/ast_build.h>
#include <isl/schedule.h>
#include <isl/schedule_node.h>

#include <tiramisu/debug.h>
#include <tiramisu/core.h>

#include <string.h>
#include <Halide.h>
#include "halide_image_io.h"

/* Halide code.
Func blurxy(Func input, Func blur_y) {
    Func blur_x;
    Var x, y, xi, yi;

    // The algorithm - no storage or order
    blur_x(x, y) = (input(x-1, y) + input(x, y) + input(x+1, y))/3;
    blur_y(x, y) = (blur_x(x, y-1) + blur_x(x, y) + blur_x(x, y+1))/3;

    // The schedule - defines order, locality; implies storage
    blur_y.tile(x, y, xi, yi, 256, 32)
        .vectorize(xi, 8).parallel(y);
    blur_x.compute_at(blur_y, x).vectorize(x, 8);
  }
*/

#define SIZE0 1280
#define SIZE1 768

using namespace tiramisu;

int main(int argc, char **argv)
{
    // Set default tiramisu options.
    global::set_default_tiramisu_options();

    // -------------------------------------------------------
    // Layer I
    // -------------------------------------------------------

    /*
     * Declare a function blurxy.
     * Declare two arguments (tiramisu buffers) for the function: b_input and b_blury
     * Declare an invariant for the function.
     */
    function blurxy("blurxy");

    constant p0("N", expr((int32_t) SIZE0), p_int32, true, NULL, 0, &blurxy);
    constant p1("M", expr((int32_t) SIZE1), p_int32, true, NULL, 0, &blurxy);

    // Declare a wrapper around the input.
    computation c_input("[N]->{c_input[i,j]: 0<=i<N and 0<=j<N}", expr(), false, p_uint8, &blurxy);

    var i("i"), j("j"), i0("i0"), i1("i1"), j0("j0"), j1("j1");

    // Declare the computations c_blurx and c_blury.
    expr e1 = (c_input(i - 1, j) +
               c_input(i    , j) +
               c_input(i + 1, j)) / ((uint8_t) 3);

    computation c_blurx("[N,M]->{c_blurx[i,j]: 0<i<N and 0<j<M}", e1, true, p_uint8, &blurxy);

    expr e2 = (c_blurx(i, j - 1) +
               c_blurx(i, j) +
               c_blurx(i, j + 1)) / ((uint8_t) 3);

    computation c_blury("[N,M]->{c_blury[i,j]: 1<i<N-1 and 1<j<M-1}", e2, true, p_uint8, &blurxy);

    // -------------------------------------------------------
    // Layer II
    // -------------------------------------------------------

    // Set the schedule of each computation.
    c_blurx.tile(i, j, 2, 2, i0, j0, i1, j1);
    c_blurx.tag_parallel_level(i0);
    c_blury.after(c_blurx, computation::root);

    // -------------------------------------------------------
    // Layer III
    // -------------------------------------------------------

    buffer b_input("b_input", {tiramisu::expr(SIZE0), tiramisu::expr(SIZE1)}, p_uint8, a_input, &blurxy);
    buffer b_blury("b_blury", {tiramisu::expr(SIZE0), tiramisu::expr(SIZE1)}, p_uint8, a_output, &blurxy);
    buffer b_blurx("b_blurx", {tiramisu::expr(SIZE0), tiramisu::expr(SIZE1)}, p_uint8, a_temporary, &blurxy);

    // Map the computations to a buffer.
    c_input.set_access("{c_input[i,j]->b_input[i,j]}");
    c_blurx.set_access("{c_blurx[i,j]->b_blurx[i,j]}");
    c_blury.set_access("{c_blury[i,j]->b_blury[i,j]}");

    // -------------------------------------------------------
    // Code Generation
    // -------------------------------------------------------

    // Set the arguments to blurxy
    blurxy.set_arguments({&b_input, &b_blury});
    // Generate code
    blurxy.gen_time_space_domain();
    blurxy.gen_isl_ast();
    blurxy.gen_halide_stmt();
    blurxy.gen_halide_obj("build/generated_fct_developers_tutorial_02.o");

    // Some debugging
    blurxy.dump_iteration_domain();
    blurxy.dump_halide_stmt();

    // Dump all the fields of the blurxy class.
    blurxy.dump(true);

    return 0;
}
<commit_msg>Update tutorial_02.cpp<commit_after>#include <isl/set.h>
#include <isl/union_map.h>
#include <isl/union_set.h>
#include <isl/ast_build.h>
#include <isl/schedule.h>
#include <isl/schedule_node.h>

#include <tiramisu/debug.h>
#include <tiramisu/core.h>

#include <string.h>
#include <Halide.h>
#include "halide_image_io.h"

/* Halide code.
Func blurxy(Func input, Func blur_y) {
    Func blur_x;
    Var x, y, xi, yi;

    // The algorithm - no storage or order
    blur_x(x, y) = (input(x-1, y) + input(x, y) + input(x+1, y))/3;
    blur_y(x, y) = (blur_x(x, y-1) + blur_x(x, y) + blur_x(x, y+1))/3;

    // The schedule - defines order, locality; implies storage
    blur_y.tile(x, y, xi, yi, 256, 32)
        .vectorize(xi, 8).parallel(y);
    blur_x.compute_at(blur_y, x).vectorize(x, 8);
  }
*/

#define SIZE0 1280
#define SIZE1 768

using namespace tiramisu;

int main(int argc, char **argv)
{
    // Set default tiramisu options.
    global::set_default_tiramisu_options();

    // -------------------------------------------------------
    // Layer I
    // -------------------------------------------------------

    /*
     * Declare a function blurxy.
     * Declare two arguments (tiramisu buffers) for the function: b_input and b_blury
     * Declare an invariant for the function.
     */
    function blurxy("blurxy");

    constant p0("N", expr((int32_t) SIZE0), p_int32, true, NULL, 0, &blurxy);
    constant p1("M", expr((int32_t) SIZE1), p_int32, true, NULL, 0, &blurxy);

    // Declare a wrapper around the input.
    computation c_input("[N]->{c_input[i,j]: 0<=i<N and 0<=j<N}", expr(), false, p_uint8, &blurxy);

    var i("i"), j("j"), i0("i0"), i1("i1"), j0("j0"), j1("j1");

    // Declare the computations c_blurx and c_blury.
    expr e1 = (c_input(i - 1, j) +
               c_input(i    , j) +
               c_input(i + 1, j)) / ((uint8_t) 3);

    computation c_blurx("[N,M]->{c_blurx[i,j]: 0<i<N and 0<j<M}", e1, true, p_uint8, &blurxy);

    expr e2 = (c_blurx(i, j - 1) +
               c_blurx(i, j) +
               c_blurx(i, j + 1)) / ((uint8_t) 3);

    computation c_blury("[N,M]->{c_blury[i,j]: 1<i<N-1 and 1<j<M-1}", e2, true, p_uint8, &blurxy);

    // -------------------------------------------------------
    // Layer II
    // -------------------------------------------------------

    // Set the schedule of each computation.
    c_blurx.tile(i, j, 2, 2, i0, j0, i1, j1);
    c_blurx.tag_parallel_level(i0);
    c_blury.after(c_blurx, computation::root);

    // -------------------------------------------------------
    // Layer III
    // -------------------------------------------------------

    buffer b_input("b_input", {tiramisu::expr(SIZE0), tiramisu::expr(SIZE1)}, p_uint8, a_input, &blurxy);
    buffer b_blury("b_blury", {tiramisu::expr(SIZE0), tiramisu::expr(SIZE1)}, p_uint8, a_output, &blurxy);
    buffer b_blurx("b_blurx", {tiramisu::expr(SIZE0), tiramisu::expr(SIZE1)}, p_uint8, a_temporary, &blurxy);

    // Map the computations to a buffer.
    c_input.set_access("{c_input[i,j]->b_input[i,j]}");
    c_blurx.set_access("{c_blurx[i,j]->b_blurx[i,j]}");
    c_blury.set_access("{c_blury[i,j]->b_blury[i,j]}");

    // -------------------------------------------------------
    // Code Generation
    // -------------------------------------------------------

    // Set the arguments to blurxy
    blurxy.set_arguments({&b_input, &b_blury});
    // Generate code
    blurxy.gen_time_space_domain();
    blurxy.gen_isl_ast();
    blurxy.gen_halide_stmt();
    blurxy.gen_halide_obj("build/generated_fct_developers_tutorial_02.o");

    // Some debugging
    blurxy.dump_iteration_domain();
    blurxy.dump_halide_stmt();

    // Dump all the fields of the blurxy class.
    blurxy.dump(true);

    return 0;
}
/**
 * Current limitations:
 * - Note that the type of the invariants N and M are "int32_t". This is
 *   important because these invariants are used later as loop bounds and the
 *   type of the bounds and the iterators should be the same for correct code
 *   generation. This implies that the invariants should be of type "int32_t".
 */
<|endoftext|>


<commit_before>/* -*- c-basic-offset: 2; coding: utf-8 -*- */
/*
  Copyright (C) 2011  Brazil

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License version 2.1 as published by the Free Software Foundation.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <gcutter.h>
#include <cppcutter.h>

#include <grn-assertions.h>
#include <dat/key-cursor.hpp>
#include <dat/trie.hpp>

namespace test_dat_key_cursor
{
}
<commit_msg>add a test of grn::dat::KeyCursor.<commit_after>/* -*- c-basic-offset: 2; coding: utf-8 -*- */
/*
  Copyright (C) 2011  Brazil

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License version 2.1 as published by the Free Software Foundation.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <gcutter.h>
#include <cppcutter.h>

#include <grn-assertions.h>
#include <dat/key-cursor.hpp>
#include <dat/trie.hpp>

#include <cstring>

namespace
{
  void create_trie(grn::dat::Trie *trie)
  {
    trie->create();
    trie->insert("Werdna", std::strlen("Werdna"));  // ID: 1, 7th
    trie->insert("Trebor", std::strlen("Trebor"));  // ID: 2, 6th
    trie->insert("Human", std::strlen("Human"));    // ID: 3, 5th
    trie->insert("Elf", std::strlen("Elf"));        // ID: 4, 2nd
    trie->insert("Dwarf", std::strlen("Dward"));    // ID: 5, 1st
    trie->insert("Gnome", std::strlen("Gnome"));    // ID: 6, 3rd
    trie->insert("Hobbit", std::strlen("Hobbit"));  // ID: 7, 4th
  }
}

namespace test_dat_key_cursor
{
  void test_null(void)
  {
    grn::dat::Trie trie;
    create_trie(&trie);

    grn::dat::KeyCursor cursor;
    cursor.open(trie, grn::dat::String(), grn::dat::String());
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(5));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(4));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(6));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(7));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(2));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(1));
    cppcut_assert_equal(cursor.next().is_valid(), false);
  }

  void test_min(void)
  {
    grn::dat::Trie trie;
    create_trie(&trie);

    grn::dat::KeyCursor cursor;

    cursor.open(trie, grn::dat::String("Hobbit"), grn::dat::String());
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(7));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(2));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(1));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String("T"), grn::dat::String());
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(2));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(1));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String("Z"), grn::dat::String());
    cppcut_assert_equal(cursor.next().is_valid(), false);
  }

  void test_max_by_str(void)
  {
    grn::dat::Trie trie;
    create_trie(&trie);

    grn::dat::KeyCursor cursor;

    cursor.open(trie, grn::dat::String(), grn::dat::String("Elf"));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(5));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(4));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String(), grn::dat::String("F"));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(5));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(4));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String(), grn::dat::String("A"));
    cppcut_assert_equal(cursor.next().is_valid(), false);
  }

  void test_min_max(void)
  {
    grn::dat::Trie trie;
    create_trie(&trie);

    grn::dat::KeyCursor cursor;
    cursor.open(trie, grn::dat::String("Gnome"), grn::dat::String("Trebor"));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(6));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(7));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(2));
    cppcut_assert_equal(cursor.next().is_valid(), false);
  }

  void test_offset(void)
  {
    grn::dat::Trie trie;
    create_trie(&trie);

    grn::dat::KeyCursor cursor;

    cursor.open(trie, grn::dat::String("Hobbit"), grn::dat::String("Trebor"), 0);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(7));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(2));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String(), grn::dat::String(), 5);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(2));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(1));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String("Gnome"), grn::dat::String("Trebor"), 2);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(2));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String("Gnome"), grn::dat::String("Trebor"), 100);
    cppcut_assert_equal(cursor.next().is_valid(), false);
  }

  void test_limit(void)
  {
    grn::dat::Trie trie;
    create_trie(&trie);

    grn::dat::KeyCursor cursor;

    cursor.open(trie, grn::dat::String("Gnome"), grn::dat::String("Werdna"),
                0, grn::dat::UINT32_MAX);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(6));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(7));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(2));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(1));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String("Gnome"), grn::dat::String("Werdna"),
                0, 3);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(6));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(7));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String("A"), grn::dat::String("Z"), 3, 2);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(7));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String("A"), grn::dat::String("Z"), 0, 0);
    cppcut_assert_equal(cursor.next().is_valid(), false);
  }

  void test_ascending_cursor(void)
  {
    grn::dat::Trie trie;
    create_trie(&trie);

    grn::dat::KeyCursor cursor;

    cursor.open(trie, grn::dat::String(), grn::dat::String(),
                0, grn::dat::UINT32_MAX, grn::dat::ASCENDING_CURSOR);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(5));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(4));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(6));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(7));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(2));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(1));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String("Elf"), grn::dat::String("Human"),
                0, grn::dat::UINT32_MAX, grn::dat::ASCENDING_CURSOR);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(4));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(6));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(7));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String("Dwarf"), grn::dat::String("Trebor"),
                3, 2, grn::dat::ASCENDING_CURSOR);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(7));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().is_valid(), false);
  }

  void test_descending_cursor(void)
  {
    grn::dat::Trie trie;
    create_trie(&trie);

    grn::dat::KeyCursor cursor;

    cursor.open(trie, grn::dat::String(), grn::dat::String(),
                0, grn::dat::UINT32_MAX, grn::dat::DESCENDING_CURSOR);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(1));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(2));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(7));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(6));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(4));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(5));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String("Elf"), grn::dat::String("Human"),
                0, grn::dat::UINT32_MAX, grn::dat::DESCENDING_CURSOR);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(7));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(6));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(4));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String("Dwarf"), grn::dat::String("Trebor"),
                3, 2, grn::dat::DESCENDING_CURSOR);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(6));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(4));
    cppcut_assert_equal(cursor.next().is_valid(), false);
  }

  void test_except_boundary(void)
  {
    grn::dat::Trie trie;
    create_trie(&trie);

    grn::dat::KeyCursor cursor;

    cursor.open(trie, grn::dat::String(), grn::dat::String(),
                0, grn::dat::UINT32_MAX,
                grn::dat::EXCEPT_LOWER_BOUND | grn::dat::EXCEPT_UPPER_BOUND);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(5));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(4));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(6));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(7));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(2));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(1));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String("Dwarf"), grn::dat::String("Werdna"),
                0, grn::dat::UINT32_MAX,
                grn::dat::EXCEPT_LOWER_BOUND | grn::dat::EXCEPT_UPPER_BOUND);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(4));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(6));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(7));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(2));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String("Elf"), grn::dat::String("Trebor"),
                2, 100, grn::dat::EXCEPT_LOWER_BOUND);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(2));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String("Elf"), grn::dat::String("Trebor"),
                2, 100, grn::dat::EXCEPT_UPPER_BOUND);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(7));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().is_valid(), false);

    cursor.open(trie, grn::dat::String("Fighter"), grn::dat::String("Samurai"),
                0, grn::dat::UINT32_MAX,
                grn::dat::EXCEPT_LOWER_BOUND | grn::dat::EXCEPT_UPPER_BOUND);
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(6));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(7));
    cppcut_assert_equal(cursor.next().id(), grn::dat::UInt32(3));
    cppcut_assert_equal(cursor.next().is_valid(), false);
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
// Class header file.
#include "FormatterToXercesDOM.hpp"

#include <cassert>

#include <xercesc/sax/AttributeList.hpp>

#include <xercesc/dom/DOMCDATASection.hpp>
#include <xercesc/dom/DOMComment.hpp>
#include <xercesc/dom/DOMDocument.hpp>
#include <xercesc/dom/DOMDocumentFragment.hpp>
#include <xercesc/dom/DOMElement.hpp>
#include <xercesc/dom/DOMEntityReference.hpp>
#include <xercesc/dom/DOMProcessingInstruction.hpp>
#include <xercesc/dom/DOMText.hpp>

#include <xalanc/XalanDOM/XalanDOMString.hpp>

#include <xalanc/DOMSupport/DOMServices.hpp>

#include <xalanc/PlatformSupport/DOMStringHelper.hpp>
#include <xalanc/PlatformSupport/PrefixResolver.hpp>

#include "XercesDOMException.hpp"

XALAN_CPP_NAMESPACE_BEGIN

const XalanDOMString	FormatterToXercesDOM::s_emptyString(XalanMemMgrs::getDummyMemMgr());

FormatterToXercesDOM::FormatterToXercesDOM(
			DOMDocument_Type*			doc,
			DOMDocumentFragmentType*	docFrag,
			DOMElementType*				currentElement,
            MemoryManagerType&          theManager) :
	FormatterListener(OUTPUT_METHOD_DOM),
	m_doc(doc),
	m_docFrag(docFrag),
	m_currentElem(currentElement),
	m_elemStack(theManager),
	m_buffer(theManager),
	m_textBuffer(theManager)
{
	assert(m_doc != 0 && m_docFrag != 0);
}

FormatterToXercesDOM::FormatterToXercesDOM(
			DOMDocument_Type*	doc,
			DOMElementType*		elem,
            MemoryManagerType& theManager) :
	FormatterListener(OUTPUT_METHOD_DOM),
	m_doc(doc),
	m_docFrag(0),
	m_currentElem(elem),
	m_elemStack(theManager),
	m_buffer(theManager),
	m_textBuffer(theManager)
{
	assert(m_doc != 0);
}

FormatterToXercesDOM::~FormatterToXercesDOM()
{
}

void
FormatterToXercesDOM::setDocumentLocator(const LocatorType* const	/* locator */)
{
	// No action for the moment.
}

void
FormatterToXercesDOM::startDocument()
{
	// No action for the moment.
}

void
FormatterToXercesDOM::endDocument()
{
	// No action for the moment.
}

void
FormatterToXercesDOM::startElement(
			const	XMLCh* const	name,
			AttributeListType&		attrs)
{
	try
	{
		processAccumulatedText();

		DOMElementType* const	elem = createElement(name, attrs);
		assert(elem != 0);

		append(elem);

		m_elemStack.push_back(m_currentElem);

		m_currentElem = elem;
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::endElement(const	XMLCh* const	/* name */)
{
	try
	{
		processAccumulatedText();

		if(m_elemStack.empty() == false)
		{
			m_currentElem = m_elemStack.back();

			m_elemStack.pop_back();
		}
		else
		{
			m_currentElem = 0;
		}
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::characters(
			const XMLCh* const	chars,
			const unsigned int	length)
{
	m_textBuffer.append(chars, length);
}

void
FormatterToXercesDOM::charactersRaw(
		const XMLCh* const	chars,
		const unsigned int	length)
{
	try
	{
		processAccumulatedText();

		cdata(chars, length);
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::entityReference(const XMLCh* const	name)
{
	try
	{
		processAccumulatedText();

		append(m_doc->createEntityReference(name));
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::ignorableWhitespace(
			const XMLCh* const	chars,
			const unsigned int	length)
{
	try
	{
		processAccumulatedText();

		assign(m_buffer, chars, length);

		append(m_doc->createTextNode(m_buffer.c_str()));
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::processingInstruction(
			const XMLCh* const	target,
			const XMLCh* const	data)
{
	try
	{
		processAccumulatedText();

		append(m_doc->createProcessingInstruction(target, data));
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::resetDocument()
{
}

void
FormatterToXercesDOM::comment(const XMLCh* const	data)
{
	try
	{
		processAccumulatedText();

		append(m_doc->createComment(data));
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::cdata(
			const XMLCh* const	ch,
			const unsigned int 	length)
{
	try
	{
		processAccumulatedText();

		assign(m_buffer, ch, length);

		append(m_doc->createCDATASection(m_buffer.c_str()));
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::append(DOMNodeType*	newNode)
{
	assert(newNode != 0);

	if(0 != m_currentElem)
	{
		m_currentElem->appendChild(newNode);
	}
	else if(0 != m_docFrag)
	{
		m_docFrag->appendChild(newNode);
	}
	else
	{
		m_doc->appendChild(newNode);
	}
}

DOMElementType*
FormatterToXercesDOM::createElement(
			const XalanDOMChar*		theElementName,
			AttributeListType&		attrs)
{
	DOMElementType*	theElement = 0;

	if (m_prefixResolver == 0)
	{
		theElement = m_doc->createElement(theElementName);

		addAttributes(theElement, attrs);
	}
	else
	{
		// Check for the namespace...
		const XalanDOMString* const		theNamespace =
				DOMServices::getNamespaceForPrefix(theElementName, *m_prefixResolver, false, m_buffer);

		if (theNamespace == 0 || length(*theNamespace) == 0)
		{
			theElement = m_doc->createElement(theElementName);
		}
		else
		{
			theElement = m_doc->createElementNS(theNamespace->c_str(), theElementName);
		}

		addAttributes(theElement, attrs);
	}

	return theElement;
}

void
FormatterToXercesDOM::addAttributes(
			DOMElementType*		theElement,
			AttributeListType&	attrs)
{
	const unsigned int	nAtts = attrs.getLength();

	if (m_prefixResolver == 0)
	{
		for(unsigned int i = 0; i < nAtts; i++)
		{
			theElement->setAttribute(attrs.getName(i), attrs.getValue(i));
		}
	}
	else
	{
		for(unsigned int i = 0; i < nAtts; i++)
		{
			const XalanDOMChar* const	theName = attrs.getName(i);
			assert(theName != 0);

			// Check for the namespace...
			const XalanDOMString* const		theNamespace =
					DOMServices::getNamespaceForPrefix(theName, *m_prefixResolver, true, m_buffer);

			if (theNamespace == 0 || length(*theNamespace) == 0)
			{
				theElement->setAttribute(theName, attrs.getValue(i));
			}
			else
			{
				theElement->setAttributeNS(theNamespace->c_str(), theName, attrs.getValue(i));
			}
		}
	}
}

void
FormatterToXercesDOM::processAccumulatedText()
{
	if (isEmpty(m_textBuffer) == false)
	{
		append(m_doc->createTextNode(m_textBuffer.c_str()));

		clear(m_textBuffer);
	}
}

XALAN_CPP_NAMESPACE_END
<commit_msg>Fixes for XALANC-530.<commit_after>/*
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
// Class header file.
#include "FormatterToXercesDOM.hpp"

#include <cassert>

#include <xercesc/sax/AttributeList.hpp>

#include <xercesc/dom/DOMCDATASection.hpp>
#include <xercesc/dom/DOMComment.hpp>
#include <xercesc/dom/DOMDocument.hpp>
#include <xercesc/dom/DOMDocumentFragment.hpp>
#include <xercesc/dom/DOMElement.hpp>
#include <xercesc/dom/DOMEntityReference.hpp>
#include <xercesc/dom/DOMProcessingInstruction.hpp>
#include <xercesc/dom/DOMText.hpp>

#include <xalanc/XalanDOM/XalanDOMString.hpp>

#include <xalanc/DOMSupport/DOMServices.hpp>

#include <xalanc/PlatformSupport/DOMStringHelper.hpp>
#include <xalanc/PlatformSupport/PrefixResolver.hpp>

#include "XercesDOMException.hpp"

XALAN_CPP_NAMESPACE_BEGIN

const XalanDOMString	FormatterToXercesDOM::s_emptyString(XalanMemMgrs::getDummyMemMgr());

FormatterToXercesDOM::FormatterToXercesDOM(
			DOMDocument_Type*			doc,
			DOMDocumentFragmentType*	docFrag,
			DOMElementType*				currentElement,
            MemoryManagerType&          theManager) :
	FormatterListener(OUTPUT_METHOD_DOM),
	m_doc(doc),
	m_docFrag(docFrag),
	m_currentElem(currentElement),
	m_elemStack(theManager),
	m_buffer(theManager),
	m_textBuffer(theManager)
{
	assert(m_doc != 0 && m_docFrag != 0);
}

FormatterToXercesDOM::FormatterToXercesDOM(
			DOMDocument_Type*	doc,
			DOMElementType*		elem,
            MemoryManagerType& theManager) :
	FormatterListener(OUTPUT_METHOD_DOM),
	m_doc(doc),
	m_docFrag(0),
	m_currentElem(elem),
	m_elemStack(theManager),
	m_buffer(theManager),
	m_textBuffer(theManager)
{
	assert(m_doc != 0);
}

FormatterToXercesDOM::~FormatterToXercesDOM()
{
}

void
FormatterToXercesDOM::setDocumentLocator(const LocatorType* const	/* locator */)
{
	// No action for the moment.
}

void
FormatterToXercesDOM::startDocument()
{
	// No action for the moment.
}

void
FormatterToXercesDOM::endDocument()
{
	try
	{
        // Process any remaining text, in case we're
        // appending to a DOMDocumentFragment.
        processAccumulatedText();
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::startElement(
			const	XMLCh* const	name,
			AttributeListType&		attrs)
{
	try
	{
		processAccumulatedText();

		DOMElementType* const	elem = createElement(name, attrs);
		assert(elem != 0);

		append(elem);

		m_elemStack.push_back(m_currentElem);

		m_currentElem = elem;
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::endElement(const	XMLCh* const	/* name */)
{
	try
	{
		processAccumulatedText();

		if(m_elemStack.empty() == false)
		{
			m_currentElem = m_elemStack.back();

			m_elemStack.pop_back();
		}
		else
		{
			m_currentElem = 0;
		}
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::characters(
			const XMLCh* const	chars,
			const unsigned int	length)
{
	m_textBuffer.append(chars, length);
}

void
FormatterToXercesDOM::charactersRaw(
		const XMLCh* const	chars,
		const unsigned int	length)
{
	try
	{
		processAccumulatedText();

		cdata(chars, length);
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::entityReference(const XMLCh* const	name)
{
	try
	{
		processAccumulatedText();

		append(m_doc->createEntityReference(name));
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::ignorableWhitespace(
			const XMLCh* const	chars,
			const unsigned int	length)
{
	try
	{
		processAccumulatedText();

		assign(m_buffer, chars, length);

		append(m_doc->createTextNode(m_buffer.c_str()));
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::processingInstruction(
			const XMLCh* const	target,
			const XMLCh* const	data)
{
	try
	{
		processAccumulatedText();

		append(m_doc->createProcessingInstruction(target, data));
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::resetDocument()
{
}

void
FormatterToXercesDOM::comment(const XMLCh* const	data)
{
	try
	{
		processAccumulatedText();

		append(m_doc->createComment(data));
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::cdata(
			const XMLCh* const	ch,
			const unsigned int 	length)
{
	try
	{
		processAccumulatedText();

		assign(m_buffer, ch, length);

		append(m_doc->createCDATASection(m_buffer.c_str()));
	}
	catch(const XERCES_CPP_NAMESPACE_QUALIFIER DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}

void
FormatterToXercesDOM::append(DOMNodeType*	newNode)
{
	assert(newNode != 0);

	if(0 != m_currentElem)
	{
		m_currentElem->appendChild(newNode);
	}
	else if(0 != m_docFrag)
	{
		m_docFrag->appendChild(newNode);
	}
	else
	{
		m_doc->appendChild(newNode);
	}
}

DOMElementType*
FormatterToXercesDOM::createElement(
			const XalanDOMChar*		theElementName,
			AttributeListType&		attrs)
{
	DOMElementType*	theElement = 0;

	if (m_prefixResolver == 0)
	{
		theElement = m_doc->createElement(theElementName);

		addAttributes(theElement, attrs);
	}
	else
	{
		// Check for the namespace...
		const XalanDOMString* const		theNamespace =
				DOMServices::getNamespaceForPrefix(theElementName, *m_prefixResolver, false, m_buffer);

		if (theNamespace == 0 || length(*theNamespace) == 0)
		{
			theElement = m_doc->createElement(theElementName);
		}
		else
		{
			theElement = m_doc->createElementNS(theNamespace->c_str(), theElementName);
		}

		addAttributes(theElement, attrs);
	}

	return theElement;
}

void
FormatterToXercesDOM::addAttributes(
			DOMElementType*		theElement,
			AttributeListType&	attrs)
{
	const unsigned int	nAtts = attrs.getLength();

	if (m_prefixResolver == 0)
	{
		for(unsigned int i = 0; i < nAtts; i++)
		{
			theElement->setAttribute(attrs.getName(i), attrs.getValue(i));
		}
	}
	else
	{
		for(unsigned int i = 0; i < nAtts; i++)
		{
			const XalanDOMChar* const	theName = attrs.getName(i);
			assert(theName != 0);

			// Check for the namespace...
			const XalanDOMString* const		theNamespace =
					DOMServices::getNamespaceForPrefix(theName, *m_prefixResolver, true, m_buffer);

			if (theNamespace == 0 || length(*theNamespace) == 0)
			{
				theElement->setAttribute(theName, attrs.getValue(i));
			}
			else
			{
				theElement->setAttributeNS(theNamespace->c_str(), theName, attrs.getValue(i));
			}
		}
	}
}

void
FormatterToXercesDOM::processAccumulatedText()
{
	if (isEmpty(m_textBuffer) == false)
	{
		append(m_doc->createTextNode(m_textBuffer.c_str()));

		clear(m_textBuffer);
	}
}

XALAN_CPP_NAMESPACE_END
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#ifndef FUTURE_HH_
#define FUTURE_HH_

#include "apply.hh"
#include <stdexcept>
#include <memory>

template <class... T>
class promise;

template <class... T>
class future;

template <typename... T, typename... A>
future<T...> make_ready_future(A&&... value);

template <typename... T>
future<T...> make_exception_future(std::exception_ptr value);

class task {
public:
    virtual ~task() {}
    virtual void run() = 0;
};

void schedule(std::unique_ptr<task> t);

template <typename Func>
class lambda_task : public task {
    Func _func;
public:
    lambda_task(const Func& func) : _func(func) {}
    lambda_task(Func&& func) : _func(std::move(func)) {}
    virtual void run() { _func(); }
};

template <typename Func>
std::unique_ptr<task>
make_task(const Func& func) {
    return std::unique_ptr<task>(new lambda_task<Func>(func));
}

template <typename Func>
std::unique_ptr<task>
make_task(Func&& func) {
    return std::unique_ptr<task>(new lambda_task<Func>(std::move(func)));
}

//
// A future/promise pair maintain one logical value (a future_state).
// To minimize allocations, the value is stored in exactly one of three
// locations:
//
// - in the promise (so long as it exists, and before a .then() is called)
//
// - in the task associated with the .then() clause (after .then() is called,
//   if a value was not set)
//
// - in the future (if the promise was destroyed, or if it never existed, as
//   with make_ready_future()), before .then() is called
//
// Both promise and future maintain a pointer to the state, which is modified
// the the state moves to a new location due to events (such as .then() being
// called) or due to the promise or future being mobved around.
//

template <typename... T>
struct future_state {
    enum class state {
         invalid,
         future,
         result,
         exception,
    } _state = state::future;
    union any {
        any() {}
        ~any() {}
        std::tuple<T...> value;
        std::exception_ptr ex;
    } _u;
    future_state() = default;
    future_state(future_state&& x) : _state(x._state) {
        switch (_state) {
        case state::future:
            break;
        case state::result:
            new (&_u.value) std::tuple<T...>(std::move(x._u.value));
            break;
        case state::exception:
            new (&_u.ex) std::exception_ptr(std::move(x._u.ex));
            break;
        case state::invalid:
            break;
        default:
            abort();
        }
    }
    ~future_state() noexcept {
        switch (_state) {
        case state::invalid:
            break;
        case state::future:
            break;
        case state::result:
            _u.value.~tuple();
            break;
        case state::exception:
            _u.ex.~exception_ptr();
            break;
        default:
            abort();
        }
    }
    future_state& operator=(future_state&& x) {
        if (this != &x) {
            this->~future_state();
            new (this) future_state(std::move(x));
        }
        return *this;
    }
    bool available() const { return _state == state::result || _state == state::exception; }
    void wait();
    void set(const std::tuple<T...>& value) {
        assert(_state == state::future);
        _state = state::result;
        new (&_u.value) std::tuple<T...>(value);
    }
    void set(std::tuple<T...>&& value) {
        assert(_state == state::future);
        _state = state::result;
        new (&_u.value) std::tuple<T...>(std::move(value));
    }
    template <typename... A>
    void set(A&&... a) {
        assert(_state == state::future);
        _state = state::result;
        new (&_u.value) std::tuple<T...>(std::forward<A>(a)...);
    }
    void set_exception(std::exception_ptr ex) {
        assert(_state == state::future);
        _state = state::exception;
        new (&_u.ex) std::exception_ptr(ex);
    }
    std::tuple<T...> get() {
        assert(_state != state::future);
        if (_state == state::exception) {
            std::rethrow_exception(_u.ex);
        }
        return std::move(_u.value);
    }
};

template <typename Func, typename... T>
struct future_task final : task, future_state<T...> {
    Func _func;
    future_task(Func&& func) : _func(std::move(func)) {}
    virtual void run() {
        func(*this);
    }
};

template <typename... T>
class promise {
    future<T...>* _future = nullptr;
    future_state<T...> _local_state;
    future_state<T...>* _state;
    std::unique_ptr<task> _task;
public:
    promise() : _state(&_local_state) {}
    promise(promise&& x) : _future(x._future), _state(x._state), _task(std::move(x._task)) {
        if (_state == &x._local_state) {
            _state = &_local_state;
            _local_state = std::move(x._local_state);
        }
        x._future = nullptr;
        x._state = nullptr;
        migrated();
    }
    promise(const promise&) = delete;
    ~promise() {
        abandoned();
    }
    promise& operator=(promise&& x) {
        if (this != &x) {
            this->~promise();
            new (this) promise(std::move(x));
        }
        return *this;
    }
    void operator=(const promise&) = delete;
    future<T...> get_future();
    void set_value(const std::tuple<T...>& result) {
        _state->set(result);
        make_ready();
    }
    void set_value(std::tuple<T...>&& result) {
        _state->set(std::move(result));
        make_ready();
    }
    template <typename... A>
    void set_value(A&&... a) {
        _state->set(std::forward<A>(a)...);
        make_ready();
    }
    void set_exception(std::exception_ptr ex) {
        _state->set_exception(std::move(ex));
        make_ready();
    }
    template<typename Exception>
    void set_exception(Exception&& e) {
        set_exception(make_exception_ptr(std::forward<Exception>(e)));
    }
private:
    template <typename Func>
    void schedule(Func&& func) {
        struct task_with_state final : task {
            task_with_state(Func&& func) : _func(std::move(func)) {}
            virtual void run() override {
                _func(_state);
            }
            future_state<T...> _state;
            Func _func;
        };
        auto tws = std::make_unique<task_with_state>(std::move(func));
        _state = &tws->_state;
        _task = std::move(tws);
    }
    void make_ready();
    void migrated();
    void abandoned();

    template <typename... U>
    friend class future;
};

template <typename... T> struct is_future : std::false_type {};
template <typename... T> struct is_future<future<T...>> : std::true_type {};

struct ready_future_marker {};
struct exception_future_marker {};

template <typename... T>
class future {
    promise<T...>* _promise;
    future_state<T...> _local_state;  // valid if !_promise
private:
    future(promise<T...>* pr) : _promise(pr) {
        _promise->_future = this;
    }
    template <typename... A>
    future(ready_future_marker, A&&... a) : _promise(nullptr) {
        _local_state.set(std::forward<A>(a)...);
    }
    future(exception_future_marker, std::exception_ptr ex) : _promise(nullptr) {
        _local_state.set_exception(std::move(ex));
    }
    future_state<T...>* state() {
        return _promise ? _promise->_state : &_local_state;
    }
public:
    using value_type = std::tuple<T...>;
    using promise_type = promise<T...>;
    future(future&& x) : _promise(x._promise) {
        if (!_promise) {
            _local_state = std::move(x._local_state);
        }
        x._promise = nullptr;
        if (_promise) {
            _promise->_future = this;
        }
    }
    future(const future&) = delete;
    future& operator=(future&& x) {
        if (this != &x) {
            this->~future();
            new (this) future(std::move(x));
        }
        return *this;
    }
    void operator=(const future&) = delete;
    ~future() {
        if (_promise) {
            _promise->_future = nullptr;
        }
    }
    std::tuple<T...> get() {
        return state()->get();
    }

    bool available() {
        return state()->available();
    }

    template <typename Func, typename Enable>
    void then(Func, Enable);

    template <typename Func>
    future<> then(Func&& func,
            std::enable_if_t<std::is_same<std::result_of_t<Func(T&&...)>, void>::value, void*> = nullptr) {
        if (state()->available()) {
            try {
                apply(std::move(func), std::move(state()->get()));
                return make_ready_future<>();
            } catch (...) {
                return make_exception_future(std::current_exception());
            }
        }
        promise<> pr;
        auto fut = pr.get_future();
        _promise->schedule([pr = std::move(pr), func = std::forward<Func>(func)] (auto& state) mutable {
            try {
                apply(std::move(func), state.get());
                pr.set_value();
            } catch (...) {
                pr.set_exception(std::current_exception());
            }
        });
        _promise->_future = nullptr;
        _promise = nullptr;
        return fut;
    }

    template <typename Func>
    std::result_of_t<Func(T&&...)>
    then(Func&& func,
            std::enable_if_t<is_future<std::result_of_t<Func(T&&...)>>::value, void*> = nullptr) {
        using P = typename std::result_of_t<Func(T&&...)>::promise_type;
        if (state()->available()) {
            try {
                return apply(std::move(func), std::move(state()->get()));
            } catch (...) {
                P pr;
                pr.set_exception(std::current_exception());
                return pr.get_future();
            }
        }
        P pr;
        auto next_fut = pr.get_future();
        _promise->schedule([func = std::forward<Func>(func), pr = std::move(pr)] (auto& state) mutable {
            try {
                auto result = state.get();
                auto next_fut = apply(std::move(func), std::move(result));
                next_fut.then([pr = std::move(pr)] (auto... next) mutable {
                    pr.set_value(std::move(next)...);
                });
            } catch (...) {
                pr.set_exception(std::current_exception());
            }
        });
        _promise->_future = nullptr;
        _promise = nullptr;
        return next_fut;
    }

    template <typename Func>
    future<> rescue(Func&& func) {
        if (state()->available()) {
            try {
                func([&state = *state()] { return state.get(); });
                return make_ready_future();
            } catch (...) {
                return make_exception_future(std::current_exception());
            }
        }
        promise<> pr;
        auto f = pr.get_future();
        _promise->schedule([pr = std::move(pr), func = std::forward<Func>(func)] (auto& state) mutable {
            try {
                func([&state]() mutable { return state.get(); });
                pr.set_value();
            } catch (...) {
                pr.set_exception(std::current_exception());
            }
        });
        _promise->_future = nullptr;
        _promise = nullptr;
        return f;
    }

    template <typename... U>
    friend class promise;
    template <typename... U, typename... A>
    friend future<U...> make_ready_future(A&&... value);
    template <typename... U>
    friend future<U...> make_exception_future(std::exception_ptr ex);
    template <typename... U, typename Exception>
    friend future<U...> make_exception_future(Exception&& ex);
};

template <typename... T>
inline
future<T...>
promise<T...>::get_future()
{
    assert(!_future);
    return future<T...>(this);
}

template <typename... T>
inline
void promise<T...>::make_ready() {
    if (_task) {
        ::schedule(std::move(_task));
    }
}

template <typename... T>
inline
void promise<T...>::migrated() {
    if (_future) {
        _future->_promise = this;
    }
}

template <typename... T>
inline
void promise<T...>::abandoned() {
    if (_future) {
        assert(_state);
        assert(_state->available());
        _future->_local_state = std::move(*_state);
        _future->_promise = nullptr;
    }
}

template <typename... T, typename... A>
inline
future<T...> make_ready_future(A&&... value) {
    return future<T...>(ready_future_marker(), std::forward<A>(value)...);
}

template <typename... T>
inline
future<T...> make_exception_future(std::exception_ptr ex) {
    return future<T...>(exception_future_marker(), std::move(ex));
}

template <typename... T, typename Exception>
inline
future<T...> make_exception_future(Exception&& ex) {
    return make_exception_future<T...>(make_exception_ptr(std::forward<Exception>(ex)));
}

#endif /* FUTURE_HH_ */
<commit_msg>core: introduce future::forward_to()<commit_after>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#ifndef FUTURE_HH_
#define FUTURE_HH_

#include "apply.hh"
#include <stdexcept>
#include <memory>

template <class... T>
class promise;

template <class... T>
class future;

template <typename... T, typename... A>
future<T...> make_ready_future(A&&... value);

template <typename... T>
future<T...> make_exception_future(std::exception_ptr value);

class task {
public:
    virtual ~task() {}
    virtual void run() = 0;
};

void schedule(std::unique_ptr<task> t);

template <typename Func>
class lambda_task : public task {
    Func _func;
public:
    lambda_task(const Func& func) : _func(func) {}
    lambda_task(Func&& func) : _func(std::move(func)) {}
    virtual void run() { _func(); }
};

template <typename Func>
std::unique_ptr<task>
make_task(const Func& func) {
    return std::unique_ptr<task>(new lambda_task<Func>(func));
}

template <typename Func>
std::unique_ptr<task>
make_task(Func&& func) {
    return std::unique_ptr<task>(new lambda_task<Func>(std::move(func)));
}

//
// A future/promise pair maintain one logical value (a future_state).
// To minimize allocations, the value is stored in exactly one of three
// locations:
//
// - in the promise (so long as it exists, and before a .then() is called)
//
// - in the task associated with the .then() clause (after .then() is called,
//   if a value was not set)
//
// - in the future (if the promise was destroyed, or if it never existed, as
//   with make_ready_future()), before .then() is called
//
// Both promise and future maintain a pointer to the state, which is modified
// the the state moves to a new location due to events (such as .then() being
// called) or due to the promise or future being mobved around.
//

template <typename... T>
struct future_state {
    enum class state {
         invalid,
         future,
         result,
         exception,
    } _state = state::future;
    union any {
        any() {}
        ~any() {}
        std::tuple<T...> value;
        std::exception_ptr ex;
    } _u;
    future_state() = default;
    future_state(future_state&& x) : _state(x._state) {
        switch (_state) {
        case state::future:
            break;
        case state::result:
            new (&_u.value) std::tuple<T...>(std::move(x._u.value));
            break;
        case state::exception:
            new (&_u.ex) std::exception_ptr(std::move(x._u.ex));
            break;
        case state::invalid:
            break;
        default:
            abort();
        }
    }
    ~future_state() noexcept {
        switch (_state) {
        case state::invalid:
            break;
        case state::future:
            break;
        case state::result:
            _u.value.~tuple();
            break;
        case state::exception:
            _u.ex.~exception_ptr();
            break;
        default:
            abort();
        }
    }
    future_state& operator=(future_state&& x) {
        if (this != &x) {
            this->~future_state();
            new (this) future_state(std::move(x));
        }
        return *this;
    }
    bool available() const { return _state == state::result || _state == state::exception; }
    void wait();
    void set(const std::tuple<T...>& value) {
        assert(_state == state::future);
        _state = state::result;
        new (&_u.value) std::tuple<T...>(value);
    }
    void set(std::tuple<T...>&& value) {
        assert(_state == state::future);
        _state = state::result;
        new (&_u.value) std::tuple<T...>(std::move(value));
    }
    template <typename... A>
    void set(A&&... a) {
        assert(_state == state::future);
        _state = state::result;
        new (&_u.value) std::tuple<T...>(std::forward<A>(a)...);
    }
    void set_exception(std::exception_ptr ex) {
        assert(_state == state::future);
        _state = state::exception;
        new (&_u.ex) std::exception_ptr(ex);
    }
    std::tuple<T...> get() {
        assert(_state != state::future);
        if (_state == state::exception) {
            std::rethrow_exception(_u.ex);
        }
        return std::move(_u.value);
    }
    void forward_to(promise<T...>& pr) {
        assert(_state != state::future);
        if (_state == state::exception) {
            pr.set_exception(_u.ex);
        } else {
            pr.set_value(std::move(get()));
        }
    }
};

template <typename Func, typename... T>
struct future_task final : task, future_state<T...> {
    Func _func;
    future_task(Func&& func) : _func(std::move(func)) {}
    virtual void run() {
        func(*this);
    }
};

template <typename... T>
class promise {
    future<T...>* _future = nullptr;
    future_state<T...> _local_state;
    future_state<T...>* _state;
    std::unique_ptr<task> _task;
public:
    promise() : _state(&_local_state) {}
    promise(promise&& x) : _future(x._future), _state(x._state), _task(std::move(x._task)) {
        if (_state == &x._local_state) {
            _state = &_local_state;
            _local_state = std::move(x._local_state);
        }
        x._future = nullptr;
        x._state = nullptr;
        migrated();
    }
    promise(const promise&) = delete;
    ~promise() {
        abandoned();
    }
    promise& operator=(promise&& x) {
        if (this != &x) {
            this->~promise();
            new (this) promise(std::move(x));
        }
        return *this;
    }
    void operator=(const promise&) = delete;
    future<T...> get_future();
    void set_value(const std::tuple<T...>& result) {
        _state->set(result);
        make_ready();
    }
    void set_value(std::tuple<T...>&& result) {
        _state->set(std::move(result));
        make_ready();
    }
    template <typename... A>
    void set_value(A&&... a) {
        _state->set(std::forward<A>(a)...);
        make_ready();
    }
    void set_exception(std::exception_ptr ex) {
        _state->set_exception(std::move(ex));
        make_ready();
    }
    template<typename Exception>
    void set_exception(Exception&& e) {
        set_exception(make_exception_ptr(std::forward<Exception>(e)));
    }
private:
    template <typename Func>
    void schedule(Func&& func) {
        struct task_with_state final : task {
            task_with_state(Func&& func) : _func(std::move(func)) {}
            virtual void run() override {
                _func(_state);
            }
            future_state<T...> _state;
            Func _func;
        };
        auto tws = std::make_unique<task_with_state>(std::move(func));
        _state = &tws->_state;
        _task = std::move(tws);
    }
    void make_ready();
    void migrated();
    void abandoned();

    template <typename... U>
    friend class future;
};

template <typename... T> struct is_future : std::false_type {};
template <typename... T> struct is_future<future<T...>> : std::true_type {};

struct ready_future_marker {};
struct exception_future_marker {};

template <typename... T>
class future {
    promise<T...>* _promise;
    future_state<T...> _local_state;  // valid if !_promise
private:
    future(promise<T...>* pr) : _promise(pr) {
        _promise->_future = this;
    }
    template <typename... A>
    future(ready_future_marker, A&&... a) : _promise(nullptr) {
        _local_state.set(std::forward<A>(a)...);
    }
    future(exception_future_marker, std::exception_ptr ex) : _promise(nullptr) {
        _local_state.set_exception(std::move(ex));
    }
    future_state<T...>* state() {
        return _promise ? _promise->_state : &_local_state;
    }
public:
    using value_type = std::tuple<T...>;
    using promise_type = promise<T...>;
    future(future&& x) : _promise(x._promise) {
        if (!_promise) {
            _local_state = std::move(x._local_state);
        }
        x._promise = nullptr;
        if (_promise) {
            _promise->_future = this;
        }
    }
    future(const future&) = delete;
    future& operator=(future&& x) {
        if (this != &x) {
            this->~future();
            new (this) future(std::move(x));
        }
        return *this;
    }
    void operator=(const future&) = delete;
    ~future() {
        if (_promise) {
            _promise->_future = nullptr;
        }
    }
    std::tuple<T...> get() {
        return state()->get();
    }

    bool available() {
        return state()->available();
    }

    template <typename Func, typename Enable>
    void then(Func, Enable);

    template <typename Func>
    future<> then(Func&& func,
            std::enable_if_t<std::is_same<std::result_of_t<Func(T&&...)>, void>::value, void*> = nullptr) {
        if (state()->available()) {
            try {
                apply(std::move(func), std::move(state()->get()));
                return make_ready_future<>();
            } catch (...) {
                return make_exception_future(std::current_exception());
            }
        }
        promise<> pr;
        auto fut = pr.get_future();
        _promise->schedule([pr = std::move(pr), func = std::forward<Func>(func)] (auto& state) mutable {
            try {
                apply(std::move(func), state.get());
                pr.set_value();
            } catch (...) {
                pr.set_exception(std::current_exception());
            }
        });
        _promise->_future = nullptr;
        _promise = nullptr;
        return fut;
    }

    void forward_to(promise<T...>&& pr) {
        if (state()->available()) {
            state()->forward_to(pr);
        } else {
            _promise->schedule([pr = std::move(pr)] (auto& state) mutable {
                state.forward_to(pr);
            });
            _promise->_future = nullptr;
            _promise = nullptr;
        }
    }

    template <typename Func>
    std::result_of_t<Func(T&&...)>
    then(Func&& func,
            std::enable_if_t<is_future<std::result_of_t<Func(T&&...)>>::value, void*> = nullptr) {
        using P = typename std::result_of_t<Func(T&&...)>::promise_type;
        if (state()->available()) {
            try {
                return apply(std::move(func), std::move(state()->get()));
            } catch (...) {
                P pr;
                pr.set_exception(std::current_exception());
                return pr.get_future();
            }
        }
        P pr;
        auto next_fut = pr.get_future();
        _promise->schedule([func = std::forward<Func>(func), pr = std::move(pr)] (auto& state) mutable {
            try {
                auto result = state.get();
                auto next_fut = apply(std::move(func), std::move(result));
                next_fut.then([pr = std::move(pr)] (auto... next) mutable {
                    pr.set_value(std::move(next)...);
                });
            } catch (...) {
                pr.set_exception(std::current_exception());
            }
        });
        _promise->_future = nullptr;
        _promise = nullptr;
        return next_fut;
    }

    template <typename Func>
    future<> rescue(Func&& func) {
        if (state()->available()) {
            try {
                func([&state = *state()] { return state.get(); });
                return make_ready_future();
            } catch (...) {
                return make_exception_future(std::current_exception());
            }
        }
        promise<> pr;
        auto f = pr.get_future();
        _promise->schedule([pr = std::move(pr), func = std::forward<Func>(func)] (auto& state) mutable {
            try {
                func([&state]() mutable { return state.get(); });
                pr.set_value();
            } catch (...) {
                pr.set_exception(std::current_exception());
            }
        });
        _promise->_future = nullptr;
        _promise = nullptr;
        return f;
    }

    template <typename... U>
    friend class promise;
    template <typename... U, typename... A>
    friend future<U...> make_ready_future(A&&... value);
    template <typename... U>
    friend future<U...> make_exception_future(std::exception_ptr ex);
    template <typename... U, typename Exception>
    friend future<U...> make_exception_future(Exception&& ex);
};

template <typename... T>
inline
future<T...>
promise<T...>::get_future()
{
    assert(!_future);
    return future<T...>(this);
}

template <typename... T>
inline
void promise<T...>::make_ready() {
    if (_task) {
        ::schedule(std::move(_task));
    }
}

template <typename... T>
inline
void promise<T...>::migrated() {
    if (_future) {
        _future->_promise = this;
    }
}

template <typename... T>
inline
void promise<T...>::abandoned() {
    if (_future) {
        assert(_state);
        assert(_state->available());
        _future->_local_state = std::move(*_state);
        _future->_promise = nullptr;
    }
}

template <typename... T, typename... A>
inline
future<T...> make_ready_future(A&&... value) {
    return future<T...>(ready_future_marker(), std::forward<A>(value)...);
}

template <typename... T>
inline
future<T...> make_exception_future(std::exception_ptr ex) {
    return future<T...>(exception_future_marker(), std::move(ex));
}

template <typename... T, typename Exception>
inline
future<T...> make_exception_future(Exception&& ex) {
    return make_exception_future<T...>(make_exception_ptr(std::forward<Exception>(ex)));
}

#endif /* FUTURE_HH_ */
<|endoftext|>


<commit_before>#include <reflection/reflection.h>

// TODO:
// - REFLECTABLE
// - REFLECTABLE_MEMBER_TYPE
// - REFLECTABLE_MEMBER_FUNCTION
// - REFLECTABLE_OPERATOR
// - REFLECTABLE_OPERATOR_UNARY
// - REFLECTABLE_OPERATOR_ASSIGNMENT
// TODO:
// - free function operators (see cppreference.com)

REFLECTABLE(auto, operator!=,   member_function);
REFLECTABLE(auto, operator%,    member_function);
REFLECTABLE(auto, operator%=,   member_function);
REFLECTABLE(auto, operator&&,   member_function);
REFLECTABLE(auto, operator&,    member_function);
REFLECTABLE(auto, operator&=,   member_function);
REFLECTABLE(auto, operator(),   member_function);
REFLECTABLE(auto, operator*,    member_function);
REFLECTABLE(auto, operator*=,   member_function);
REFLECTABLE(auto, operator++,   member_function);
REFLECTABLE(auto, operator+,    member_function);
REFLECTABLE(auto, operator+=,   member_function);
REFLECTABLE(auto, operator-,    member_function);
REFLECTABLE(auto, operator--,   member_function);
REFLECTABLE(auto, operator-=,   member_function);
REFLECTABLE(auto, operator->*,  member_function);
REFLECTABLE(auto, operator/,    member_function);
REFLECTABLE(auto, operator/=,   member_function);
REFLECTABLE(auto, operator<,    member_function);
REFLECTABLE(auto, operator<<,   member_function);
REFLECTABLE(auto, operator<<=,  member_function);
REFLECTABLE(auto, operator<=,   member_function);
REFLECTABLE(auto, operator==,   member_function);
REFLECTABLE(auto, operator>,    member_function);
REFLECTABLE(auto, operator>=,   member_function);
REFLECTABLE(auto, operator>>,   member_function);
REFLECTABLE(auto, operator>>=,  member_function);
REFLECTABLE(auto, operator[],   member_function);
REFLECTABLE(auto, operator^,    member_function);
REFLECTABLE(auto, operator^=,   member_function);
REFLECTABLE(auto, operator|,    member_function);
REFLECTABLE(auto, operator|=,   member_function);
REFLECTABLE(auto, operator||,   member_function);

REFLECTION_REFLECTABLE_NONINTRUSIVE_UNARY_OPERATOR(auto, operator!,   member_function);
REFLECTION_REFLECTABLE_NONINTRUSIVE_UNARY_OPERATOR(auto, operator->,  member_function);
REFLECTION_REFLECTABLE_NONINTRUSIVE_UNARY_OPERATOR(auto, operator~,   member_function);

REFLECTION_REFLECTABLE_NONINTRUSIVE_ASSIGNMENT_OPERATOR(auto, operator=, member_function);

// TODO: operator,
// #define REFLECTION_OPERATOR_COMMA operator,
// REFLECTABLE(auto, REFLECTION_OPERATOR_COMMA,  member_function);
<commit_msg>Removed some TODOs.<commit_after>#include <reflection/reflection.h>

// TODO:
// - REFLECTABLE_OPERATOR
// - REFLECTABLE_OPERATOR_UNARY
// - REFLECTABLE_OPERATOR_ASSIGNMENT

REFLECTABLE(auto, operator!=,   member_function);
REFLECTABLE(auto, operator%,    member_function);
REFLECTABLE(auto, operator%=,   member_function);
REFLECTABLE(auto, operator&&,   member_function);
REFLECTABLE(auto, operator&,    member_function);
REFLECTABLE(auto, operator&=,   member_function);
REFLECTABLE(auto, operator(),   member_function);
REFLECTABLE(auto, operator*,    member_function);
REFLECTABLE(auto, operator*=,   member_function);
REFLECTABLE(auto, operator++,   member_function);
REFLECTABLE(auto, operator+,    member_function);
REFLECTABLE(auto, operator+=,   member_function);
REFLECTABLE(auto, operator-,    member_function);
REFLECTABLE(auto, operator--,   member_function);
REFLECTABLE(auto, operator-=,   member_function);
REFLECTABLE(auto, operator->*,  member_function);
REFLECTABLE(auto, operator/,    member_function);
REFLECTABLE(auto, operator/=,   member_function);
REFLECTABLE(auto, operator<,    member_function);
REFLECTABLE(auto, operator<<,   member_function);
REFLECTABLE(auto, operator<<=,  member_function);
REFLECTABLE(auto, operator<=,   member_function);
REFLECTABLE(auto, operator==,   member_function);
REFLECTABLE(auto, operator>,    member_function);
REFLECTABLE(auto, operator>=,   member_function);
REFLECTABLE(auto, operator>>,   member_function);
REFLECTABLE(auto, operator>>=,  member_function);
REFLECTABLE(auto, operator[],   member_function);
REFLECTABLE(auto, operator^,    member_function);
REFLECTABLE(auto, operator^=,   member_function);
REFLECTABLE(auto, operator|,    member_function);
REFLECTABLE(auto, operator|=,   member_function);
REFLECTABLE(auto, operator||,   member_function);

REFLECTION_REFLECTABLE_NONINTRUSIVE_UNARY_OPERATOR(auto, operator!,   member_function);
REFLECTION_REFLECTABLE_NONINTRUSIVE_UNARY_OPERATOR(auto, operator->,  member_function);
REFLECTION_REFLECTABLE_NONINTRUSIVE_UNARY_OPERATOR(auto, operator~,   member_function);

REFLECTION_REFLECTABLE_NONINTRUSIVE_ASSIGNMENT_OPERATOR(auto, operator=, member_function);

// TODO: operator,
// #define REFLECTION_OPERATOR_COMMA operator,
// REFLECTABLE(auto, REFLECTION_OPERATOR_COMMA,  member_function);
<|endoftext|>


<commit_before>#include "warnings-disable.h"

WARNINGS_DISABLE
#include <QtTest/QtTest>

#include <QSettings>

#include "ui_setupdialog.h"
WARNINGS_ENABLE

#include "../qtest-platform.h"

#include "utils.h"

#include <TSettings.h>

#include "compare-settings.h"

#include "setupdialog.h"

#define GET_UI_PAGE(x, PAGETYPE)                                               \
    do                                                                         \
    {                                                                          \
        x = wizard->get_ui();                                                  \
    } while(0)

#define GET_BUTTON(x) wizard->button(SetupDialog::x)

class TestSetupWizard : public QObject
{
    Q_OBJECT

private slots:
    void initTestCase();
    void cleanupTestCase();

    void normal_install();
    void cancel_install();
    void skip_install();
    void cli();
    void version_too_low();

private:
    void helper_almost_normal_install(SetupDialog *wizard);
};

void TestSetupWizard::initTestCase()
{
    QCoreApplication::setOrganizationName(TEST_NAME);

    // Use a custom message handler to filter out unwanted messages
    IF_NOT_VISUAL { qInstallMessageHandler(offscreenMessageOutput); }
}

void TestSetupWizard::cleanupTestCase()
{
    TSettings::destroy();
}

void TestSetupWizard::helper_almost_normal_install(SetupDialog *wizard)
{
    QSignalSpy sig_cli(wizard, SIGNAL(tarsnapVersionRequested()));
    QSignalSpy sig_register(wizard,
                            SIGNAL(registerMachineRequested(QString, bool)));

    Ui::SetupDialog *ui_cli;
    Ui::SetupDialog *ui_register;

    VISUAL_INIT(wizard);
    IF_NOT_VISUAL { wizard->open(); }

    // Page 1
    QVERIFY(wizard->pageTitle() == "Setup wizard");
    GET_BUTTON(NextButton)->click();
    VISUAL_WAIT;

    // Page 2
    QVERIFY(wizard->pageTitle() == "Command-line utilities");
    GET_UI_PAGE(ui_cli, CliPage);
    VISUAL_WAIT;

    // Fake the CLI detection and checking
    QVERIFY(sig_cli.count() == 1);
    wizard->tarsnapVersionResponse(TaskStatus::Completed, "X.Y.Z");
    QVERIFY(ui_cli->cliValidationLabel->text().contains("Tarsnap CLI version"));
    VISUAL_WAIT;

    // Proceed
    GET_BUTTON(NextButton)->click();
    VISUAL_WAIT;

    // Page 3
    QVERIFY(wizard->pageTitle() == "Register with server");
    GET_UI_PAGE(ui_register, RegisterPage);

    // Pretend that we already have a key
    ui_register->useExistingKeyfileButton->click();
    ui_register->machineKeyCombo->setCurrentText("empty.key");
    VISUAL_WAIT;

    // Pretend to register
    GET_BUTTON(NextButton)->click();
    QVERIFY(sig_register.count() == 1);
    wizard->updateLoadingAnimation(false);
    VISUAL_WAIT;

    // Fake a response
    wizard->registerMachineResponse(TaskStatus::Completed, "");
    VISUAL_WAIT;

    // Wait for the test to proceed (for up to 1 second)
    for(int i = 0; i < 10; i++)
    {
        if(wizard->pageTitle() == "Setup complete!")
            break;
        QTest::qWait(100);
    }

    // Page 4
    QVERIFY(wizard->pageTitle() == "Setup complete!");
    VISUAL_WAIT;
}

void TestSetupWizard::normal_install()
{
    TARSNAP_CLI_OR_SKIP;

    SetupDialog *wizard = new SetupDialog();

    // Almost complete a normal install
    helper_almost_normal_install(wizard);

    // Finish the install
    GET_BUTTON(FinishButton)->click();
    VISUAL_WAIT;

    // Check resulting init file.  The first can be in any format (for now).
    TSettings settings;
    QSettings target("after-normal-install.conf", QSettings::IniFormat);
    QVERIFY(compareSettings(settings.getQSettings(), &target));

    // Clean up
    delete wizard;
}

void TestSetupWizard::cancel_install()
{
    TARSNAP_CLI_OR_SKIP;

    SetupDialog *wizard = new SetupDialog();

    // Almost complete a normal install
    helper_almost_normal_install(wizard);

    // Close before we actually finish
    QTest::keyEvent(QTest::Click, wizard, Qt::Key_Escape);
    VISUAL_WAIT;

    // Clean up
    delete wizard;

    // Check that we wiped the Tarsnap-related settings
    TSettings  settings;
    QSettings *q = settings.getQSettings();
    q->beginGroup("tarsnap");
    QVERIFY(q->allKeys().length() == 0);
    q->beginGroup("app");
    QVERIFY(q->allKeys().length() == 0);
}

void TestSetupWizard::skip_install()
{
    TARSNAP_CLI_OR_SKIP;

    SetupDialog *wizard = new SetupDialog();

    // Almost complete a normal install
    helper_almost_normal_install(wizard);

    // Now go back to the beginning and skip the install
    GET_BUTTON(BackButton)->click();
    GET_BUTTON(BackButton)->click();
    GET_BUTTON(BackButton)->click();
    VISUAL_WAIT;

    GET_BUTTON(SkipButton)->click();
    VISUAL_WAIT;

    // Check resulting init file.
    TSettings settings;
    QSettings target("after-skip-install.conf", QSettings::IniFormat);
    QVERIFY(compareSettings(settings.getQSettings(), &target));

    // Clean up
    delete wizard;
}

void TestSetupWizard::cli()
{
    SetupDialog *    wizard = new SetupDialog();
    Ui::SetupDialog *ui_cli;

    VISUAL_INIT(wizard);
    IF_NOT_VISUAL { wizard->open(); }

    // Advance to CLI page and expand advanced options
    GET_BUTTON(NextButton)->click();
    QVERIFY(wizard->pageTitle() == "Command-line utilities");
    GET_UI_PAGE(ui_cli, CliPage);
    VISUAL_WAIT;

    // We may or may not receive a version query, depending on whether
    // tarsnap is installed, so don't check for this here.
    // (We check "did we receive a version-query signal" in other
    // tarsnap-dependent tests.)
    wizard->tarsnapVersionResponse(TaskStatus::Completed, "X.Y.Z");
    VISUAL_WAIT;

    // App data directory
    SET_TEXT_WITH_SIGNAL(ui_cli->appDataPathLineEdit, "fake-dir");
    QVERIFY(ui_cli->cliValidationLabel->text()
            == "Invalid App data directory set.");
    VISUAL_WAIT;
    SET_TEXT_WITH_SIGNAL(ui_cli->appDataPathLineEdit, "/tmp");

    // Cache directory
    SET_TEXT_WITH_SIGNAL(ui_cli->tarsnapCacheLineEdit, "fake-dir");
    QVERIFY(ui_cli->cliValidationLabel->text()
            == "Invalid Tarsnap cache directory set.");
    VISUAL_WAIT;
    SET_TEXT_WITH_SIGNAL(ui_cli->tarsnapCacheLineEdit, "/tmp");

    // Tarsnap CLI directory
    SET_TEXT_WITH_SIGNAL(ui_cli->tarsnapPathLineEdit, "fake-dir");
    QVERIFY(ui_cli->cliValidationLabel->text().contains(
        "Tarsnap utilities not found."));
    VISUAL_WAIT;
    SET_TEXT_WITH_SIGNAL(ui_cli->tarsnapPathLineEdit, "/tmp");

    // Fake detecting the binaries
    wizard->tarsnapVersionResponse(TaskStatus::Completed, "X.Y.Z");
    QVERIFY(ui_cli->cliValidationLabel->text().contains("Tarsnap CLI version"));
    VISUAL_WAIT;

    delete wizard;
}

void TestSetupWizard::version_too_low()
{
    SetupDialog *    wizard = new SetupDialog();
    Ui::SetupDialog *ui_cli;

    VISUAL_INIT(wizard);
    IF_NOT_VISUAL { wizard->open(); }

    // Advance to CLI page
    GET_BUTTON(NextButton)->click();
    QVERIFY(wizard->pageTitle() == "Command-line utilities");
    GET_UI_PAGE(ui_cli, CliPage);
    VISUAL_WAIT;

    // Fake detecting the binaries with a too-low version number
    wizard->tarsnapVersionResponse(TaskStatus::VersionTooLow, "1.0.1");
    QVERIFY(ui_cli->cliValidationLabel->text().contains("too low"));
    QVERIFY(GET_BUTTON(NextButton)->isEnabled() == false);
    QVERIFY(ui_cli->cliAdvancedWidget->isVisible() == true);
    VISUAL_WAIT;

    delete wizard;
}

QTEST_MAIN(TestSetupWizard)
#include "test-setupwizard.moc"
<commit_msg>tests/setupwizard: don't use SET_TEXT_WITH_SIGNAL<commit_after>#include "warnings-disable.h"

WARNINGS_DISABLE
#include <QtTest/QtTest>

#include <QSettings>

#include "ui_setupdialog.h"
WARNINGS_ENABLE

#include "../qtest-platform.h"

#include "utils.h"

#include <TSettings.h>

#include "compare-settings.h"

#include "setupdialog.h"

#define GET_UI_PAGE(x, PAGETYPE)                                               \
    do                                                                         \
    {                                                                          \
        x = wizard->get_ui();                                                  \
    } while(0)

#define GET_BUTTON(x) wizard->button(SetupDialog::x)

class TestSetupWizard : public QObject
{
    Q_OBJECT

private slots:
    void initTestCase();
    void cleanupTestCase();

    void normal_install();
    void cancel_install();
    void skip_install();
    void cli();
    void version_too_low();

private:
    void helper_almost_normal_install(SetupDialog *wizard);
};

void TestSetupWizard::initTestCase()
{
    QCoreApplication::setOrganizationName(TEST_NAME);

    // Use a custom message handler to filter out unwanted messages
    IF_NOT_VISUAL { qInstallMessageHandler(offscreenMessageOutput); }
}

void TestSetupWizard::cleanupTestCase()
{
    TSettings::destroy();
}

void TestSetupWizard::helper_almost_normal_install(SetupDialog *wizard)
{
    QSignalSpy sig_cli(wizard, SIGNAL(tarsnapVersionRequested()));
    QSignalSpy sig_register(wizard,
                            SIGNAL(registerMachineRequested(QString, bool)));

    Ui::SetupDialog *ui_cli;
    Ui::SetupDialog *ui_register;

    VISUAL_INIT(wizard);
    IF_NOT_VISUAL { wizard->open(); }

    // Page 1
    QVERIFY(wizard->pageTitle() == "Setup wizard");
    GET_BUTTON(NextButton)->click();
    VISUAL_WAIT;

    // Page 2
    QVERIFY(wizard->pageTitle() == "Command-line utilities");
    GET_UI_PAGE(ui_cli, CliPage);
    VISUAL_WAIT;

    // Fake the CLI detection and checking
    QVERIFY(sig_cli.count() == 1);
    wizard->tarsnapVersionResponse(TaskStatus::Completed, "X.Y.Z");
    QVERIFY(ui_cli->cliValidationLabel->text().contains("Tarsnap CLI version"));
    VISUAL_WAIT;

    // Proceed
    GET_BUTTON(NextButton)->click();
    VISUAL_WAIT;

    // Page 3
    QVERIFY(wizard->pageTitle() == "Register with server");
    GET_UI_PAGE(ui_register, RegisterPage);

    // Pretend that we already have a key
    ui_register->useExistingKeyfileButton->click();
    ui_register->machineKeyCombo->setCurrentText("empty.key");
    VISUAL_WAIT;

    // Pretend to register
    GET_BUTTON(NextButton)->click();
    QVERIFY(sig_register.count() == 1);
    wizard->updateLoadingAnimation(false);
    VISUAL_WAIT;

    // Fake a response
    wizard->registerMachineResponse(TaskStatus::Completed, "");
    VISUAL_WAIT;

    // Wait for the test to proceed (for up to 1 second)
    for(int i = 0; i < 10; i++)
    {
        if(wizard->pageTitle() == "Setup complete!")
            break;
        QTest::qWait(100);
    }

    // Page 4
    QVERIFY(wizard->pageTitle() == "Setup complete!");
    VISUAL_WAIT;
}

void TestSetupWizard::normal_install()
{
    TARSNAP_CLI_OR_SKIP;

    SetupDialog *wizard = new SetupDialog();

    // Almost complete a normal install
    helper_almost_normal_install(wizard);

    // Finish the install
    GET_BUTTON(FinishButton)->click();
    VISUAL_WAIT;

    // Check resulting init file.  The first can be in any format (for now).
    TSettings settings;
    QSettings target("after-normal-install.conf", QSettings::IniFormat);
    QVERIFY(compareSettings(settings.getQSettings(), &target));

    // Clean up
    delete wizard;
}

void TestSetupWizard::cancel_install()
{
    TARSNAP_CLI_OR_SKIP;

    SetupDialog *wizard = new SetupDialog();

    // Almost complete a normal install
    helper_almost_normal_install(wizard);

    // Close before we actually finish
    QTest::keyEvent(QTest::Click, wizard, Qt::Key_Escape);
    VISUAL_WAIT;

    // Clean up
    delete wizard;

    // Check that we wiped the Tarsnap-related settings
    TSettings  settings;
    QSettings *q = settings.getQSettings();
    q->beginGroup("tarsnap");
    QVERIFY(q->allKeys().length() == 0);
    q->beginGroup("app");
    QVERIFY(q->allKeys().length() == 0);
}

void TestSetupWizard::skip_install()
{
    TARSNAP_CLI_OR_SKIP;

    SetupDialog *wizard = new SetupDialog();

    // Almost complete a normal install
    helper_almost_normal_install(wizard);

    // Now go back to the beginning and skip the install
    GET_BUTTON(BackButton)->click();
    GET_BUTTON(BackButton)->click();
    GET_BUTTON(BackButton)->click();
    VISUAL_WAIT;

    GET_BUTTON(SkipButton)->click();
    VISUAL_WAIT;

    // Check resulting init file.
    TSettings settings;
    QSettings target("after-skip-install.conf", QSettings::IniFormat);
    QVERIFY(compareSettings(settings.getQSettings(), &target));

    // Clean up
    delete wizard;
}

void TestSetupWizard::cli()
{
    SetupDialog *    wizard = new SetupDialog();
    Ui::SetupDialog *ui_cli;

    VISUAL_INIT(wizard);
    IF_NOT_VISUAL { wizard->open(); }

    // Advance to CLI page and expand advanced options
    GET_BUTTON(NextButton)->click();
    QVERIFY(wizard->pageTitle() == "Command-line utilities");
    GET_UI_PAGE(ui_cli, CliPage);
    VISUAL_WAIT;

    // We may or may not receive a version query, depending on whether
    // tarsnap is installed, so don't check for this here.
    // (We check "did we receive a version-query signal" in other
    // tarsnap-dependent tests.)
    wizard->tarsnapVersionResponse(TaskStatus::Completed, "X.Y.Z");
    VISUAL_WAIT;

    // App data directory
    ui_cli->appDataPathLineEdit->setText("fake-dir");
    QVERIFY(ui_cli->cliValidationLabel->text()
            == "Invalid App data directory set.");
    VISUAL_WAIT;
    ui_cli->appDataPathLineEdit->setText("/tmp");

    // Cache directory
    ui_cli->tarsnapCacheLineEdit->setText("fake-dir");
    QVERIFY(ui_cli->cliValidationLabel->text()
            == "Invalid Tarsnap cache directory set.");
    VISUAL_WAIT;
    ui_cli->tarsnapCacheLineEdit->setText("/tmp");

    // Tarsnap CLI directory
    ui_cli->tarsnapPathLineEdit->setText("fake-dir");
    QVERIFY(ui_cli->cliValidationLabel->text().contains(
        "Tarsnap utilities not found."));
    VISUAL_WAIT;
    ui_cli->tarsnapPathLineEdit->setText("/tmp");

    // Fake detecting the binaries
    wizard->tarsnapVersionResponse(TaskStatus::Completed, "X.Y.Z");
    QVERIFY(ui_cli->cliValidationLabel->text().contains("Tarsnap CLI version"));
    VISUAL_WAIT;

    delete wizard;
}

void TestSetupWizard::version_too_low()
{
    SetupDialog *    wizard = new SetupDialog();
    Ui::SetupDialog *ui_cli;

    VISUAL_INIT(wizard);
    IF_NOT_VISUAL { wizard->open(); }

    // Advance to CLI page
    GET_BUTTON(NextButton)->click();
    QVERIFY(wizard->pageTitle() == "Command-line utilities");
    GET_UI_PAGE(ui_cli, CliPage);
    VISUAL_WAIT;

    // Fake detecting the binaries with a too-low version number
    wizard->tarsnapVersionResponse(TaskStatus::VersionTooLow, "1.0.1");
    QVERIFY(ui_cli->cliValidationLabel->text().contains("too low"));
    QVERIFY(GET_BUTTON(NextButton)->isEnabled() == false);
    QVERIFY(ui_cli->cliAdvancedWidget->isVisible() == true);
    VISUAL_WAIT;

    delete wizard;
}

QTEST_MAIN(TestSetupWizard)
#include "test-setupwizard.moc"
<|endoftext|>


<commit_before>#pragma once

#include "event_queue.hpp"
#include "json_utility.hpp"
#include "manipulator/details/post_event_to_virtual_devices.hpp"
#include "manipulator/manipulator_factory.hpp"
#include "manipulator/manipulator_manager.hpp"
#include "manipulator/manipulator_managers_connector.hpp"
#include "manipulator/manipulator_timer.hpp"

namespace krbn {
namespace unit_testing {
class manipulator_helper final {
public:
  static void run_tests(const nlohmann::json& json,
                        bool overwrite_expected_results = false) {
    logger::get_logger().info("krbn::unit_testing::manipulator_helper::run_tests");

    for (const auto& test : json) {
      logger::get_logger().info("{0}", test["description"].get<std::string>());

      system_preferences system_preferences;
      auto console_user_server_client = std::make_shared<krbn::console_user_server_client>();
      auto manipulator_dispatcher = std::make_shared<manipulator::manipulator_dispatcher>();
      auto manipulator_timer = std::make_shared<manipulator::manipulator_timer>(false);
      auto manipulator_object_id = manipulator::make_new_manipulator_object_id();
      manipulator::manipulator_managers_connector connector;
      std::vector<std::shared_ptr<manipulator::manipulator_manager>> manipulator_managers;
      std::vector<std::shared_ptr<event_queue>> event_queues;
      std::shared_ptr<krbn::manipulator::details::post_event_to_virtual_devices> post_event_to_virtual_devices_manipulator;

      manipulator_dispatcher->async_attach(manipulator_object_id);
      manipulator_timer->async_attach(manipulator_object_id);

      core_configuration::profile::complex_modifications::parameters parameters;
      for (const auto& rule : test["rules"]) {
        manipulator_managers.push_back(std::make_shared<manipulator::manipulator_manager>());

        {
          std::ifstream ifs(rule.get<std::string>());
          REQUIRE(ifs);
          for (const auto& j : nlohmann::json::parse(ifs)) {
            auto m = manipulator::manipulator_factory::make_manipulator(j,
                                                                        parameters,
                                                                        manipulator_dispatcher,
                                                                        manipulator_timer);

            if (auto conditions = json_utility::find_array(j, "conditions")) {
              for (const auto& c : *conditions) {
                m->push_back_condition(krbn::manipulator::manipulator_factory::make_condition(c));
              }
            }

            manipulator_managers.back()->push_back_manipulator(m);
          }
        }

        if (event_queues.empty()) {
          event_queues.push_back(std::make_shared<event_queue>());
          event_queues.push_back(std::make_shared<event_queue>());
          connector.emplace_back_connection(manipulator_managers.back(),
                                            event_queues[0],
                                            event_queues[1]);
        } else {
          event_queues.push_back(std::make_shared<event_queue>());
          connector.emplace_back_connection(manipulator_managers.back(),
                                            event_queues.back());
        }
      }

      if (json_utility::find_optional<std::string>(test, "expected_post_event_to_virtual_devices_queue")) {
        post_event_to_virtual_devices_manipulator = std::make_shared<krbn::manipulator::details::post_event_to_virtual_devices>(system_preferences,
                                                                                manipulator_dispatcher,
                                                                                manipulator_timer,
                                                                                console_user_server_client);

        manipulator_managers.push_back(std::make_unique<manipulator::manipulator_manager>());
        manipulator_managers.back()->push_back_manipulator(post_event_to_virtual_devices_manipulator);

        event_queues.push_back(std::make_shared<event_queue>());
        connector.emplace_back_connection(manipulator_managers.back(),
                                          event_queues.back());
      }

      REQUIRE(!manipulator_managers.empty());
      REQUIRE(!event_queues.empty());

      absolute_time now(0);

      auto input_event_arrived_connection = krbn_notification_center::get_instance().input_event_arrived.connect([&] {
        connector.manipulate(now);
      });

      {
        bool pause_manipulation = false;

        std::ifstream ifs(test["input_event_queue"].get<std::string>());
        REQUIRE(ifs);
        for (const auto& j : nlohmann::json::parse(ifs)) {
          if (auto s = json_utility::find_optional<std::string>(j, "action")) {
            if (*s == "invalidate_manipulators") {
              connector.invalidate_manipulators();
            } else if (*s == "invoke_manipulator_timer") {
              absolute_time time_stamp(0);
              if (auto t = json_utility::find_optional<uint64_t>(j, "time_stamp")) {
                time_stamp = absolute_time(*t);
              }
              manipulator_dispatcher->enqueue(
                  manipulator_object_id,
                  [&] {
                    manipulator_timer->async_invoke(time_stamp);
                  });
              // Wait after `async_invoke` to trigger manipulator_timer.
              std::this_thread::sleep_for(std::chrono::milliseconds(100));
            } else if (*s == "manipulate") {
              absolute_time time_stamp(0);
              if (auto t = json_utility::find_optional<uint64_t>(j, "time_stamp")) {
                time_stamp = absolute_time(*t);
              }
              connector.manipulate(time_stamp);
            } else if (*s == "sleep_milliseconds") {
              std::chrono::milliseconds ms(0);
              if (auto t = json_utility::find_optional<uint64_t>(j, "ms")) {
                ms = std::chrono::milliseconds(*t);
              }
              std::this_thread::sleep_for(ms);
            }

          } else if (auto v = json_utility::find_optional<bool>(j, "pause_manipulation")) {
            pause_manipulation = *v;
            if (!pause_manipulation) {
              connector.manipulate(now);
            }

          } else {
            auto e = event_queue::queued_event::make_from_json(j);
            now = e.get_event_time_stamp().get_time_stamp();
            event_queues.front()->push_back_event(e);
            if (!pause_manipulation) {
              connector.manipulate(now);
            }
          }
        }
      }

      std::this_thread::sleep_for(std::chrono::milliseconds(100));

      if (auto s = json_utility::find_optional<std::string>(test, "expected_event_queue")) {
        if (overwrite_expected_results) {
          std::ofstream ofs(*s);
          REQUIRE(ofs);
          ofs << nlohmann::json(event_queues.back()->get_events()).dump(4) << std::endl;
        }

        std::ifstream ifs(*s);
        REQUIRE(ifs);
        auto expected = nlohmann::json::parse(ifs);

        REQUIRE(event_queues.front()->get_events().empty());
        REQUIRE(nlohmann::json(event_queues.back()->get_events()).dump() == expected.dump());

      } else if (auto s = json_utility::find_optional<std::string>(test, "expected_post_event_to_virtual_devices_queue")) {
        if (overwrite_expected_results) {
          std::ofstream ofs(*s);
          REQUIRE(ofs);
          ofs << nlohmann::json(post_event_to_virtual_devices_manipulator->get_queue().get_events()).dump(4) << std::endl;
        }

        std::ifstream ifs(*s);
        REQUIRE(ifs);
        auto expected = nlohmann::json::parse(ifs);

        REQUIRE(post_event_to_virtual_devices_manipulator);
        REQUIRE(nlohmann::json(post_event_to_virtual_devices_manipulator->get_queue().get_events()).dump() == expected.dump());

      } else {
        logger::get_logger().error("There are not expected results.");
        REQUIRE(false);
      }

      input_event_arrived_connection.disconnect();

      manipulator_dispatcher->detach(manipulator_object_id);
      manipulator_timer->detach(manipulator_object_id);

      manipulator_managers.clear();

      manipulator_dispatcher = nullptr;
      manipulator_timer = nullptr;
    }

    logger::get_logger().info("krbn::unit_testing::manipulator_helper::run_tests finished");
  }
};
} // namespace unit_testing
} // namespace krbn
<commit_msg>update tests<commit_after>#pragma once

#include "event_queue.hpp"
#include "json_utility.hpp"
#include "manipulator/details/post_event_to_virtual_devices.hpp"
#include "manipulator/manipulator_factory.hpp"
#include "manipulator/manipulator_manager.hpp"
#include "manipulator/manipulator_managers_connector.hpp"
#include "manipulator/manipulator_timer.hpp"

namespace krbn {
namespace unit_testing {
class manipulator_helper final {
public:
  static void run_tests(const nlohmann::json& json,
                        bool overwrite_expected_results = false) {
    logger::get_logger().info("krbn::unit_testing::manipulator_helper::run_tests");

    for (const auto& test : json) {
      logger::get_logger().info("{0}", test["description"].get<std::string>());

      system_preferences system_preferences;
      auto console_user_server_client = std::make_shared<krbn::console_user_server_client>();
      auto manipulator_dispatcher = std::make_shared<manipulator::manipulator_dispatcher>();
      auto manipulator_timer = std::make_shared<manipulator::manipulator_timer>(false);
      auto manipulator_object_id = manipulator::make_new_manipulator_object_id();
      manipulator::manipulator_managers_connector connector;
      std::vector<std::shared_ptr<manipulator::manipulator_manager>> manipulator_managers;
      std::vector<std::shared_ptr<event_queue>> event_queues;
      std::shared_ptr<krbn::manipulator::details::post_event_to_virtual_devices> post_event_to_virtual_devices_manipulator;

      manipulator_dispatcher->async_attach(manipulator_object_id);
      manipulator_timer->async_attach(manipulator_object_id);

      core_configuration::profile::complex_modifications::parameters parameters;
      for (const auto& rule : test["rules"]) {
        manipulator_managers.push_back(std::make_shared<manipulator::manipulator_manager>());

        {
          std::ifstream ifs(rule.get<std::string>());
          REQUIRE(ifs);
          for (const auto& j : nlohmann::json::parse(ifs)) {
            auto m = manipulator::manipulator_factory::make_manipulator(j,
                                                                        parameters,
                                                                        manipulator_dispatcher,
                                                                        manipulator_timer);

            if (auto conditions = json_utility::find_array(j, "conditions")) {
              for (const auto& c : *conditions) {
                m->push_back_condition(krbn::manipulator::manipulator_factory::make_condition(c));
              }
            }

            manipulator_managers.back()->push_back_manipulator(m);
          }
        }

        if (event_queues.empty()) {
          event_queues.push_back(std::make_shared<event_queue>());
          event_queues.push_back(std::make_shared<event_queue>());
          connector.emplace_back_connection(manipulator_managers.back(),
                                            event_queues[0],
                                            event_queues[1]);
        } else {
          event_queues.push_back(std::make_shared<event_queue>());
          connector.emplace_back_connection(manipulator_managers.back(),
                                            event_queues.back());
        }
      }

      if (json_utility::find_optional<std::string>(test, "expected_post_event_to_virtual_devices_queue")) {
        post_event_to_virtual_devices_manipulator = std::make_shared<krbn::manipulator::details::post_event_to_virtual_devices>(system_preferences,
                                                                                manipulator_dispatcher,
                                                                                manipulator_timer,
                                                                                console_user_server_client);

        manipulator_managers.push_back(std::make_unique<manipulator::manipulator_manager>());
        manipulator_managers.back()->push_back_manipulator(post_event_to_virtual_devices_manipulator);

        event_queues.push_back(std::make_shared<event_queue>());
        connector.emplace_back_connection(manipulator_managers.back(),
                                          event_queues.back());
      }

      REQUIRE(!manipulator_managers.empty());
      REQUIRE(!event_queues.empty());

      absolute_time now(0);

      auto input_event_arrived_connection = krbn_notification_center::get_instance().input_event_arrived.connect([&] {
        connector.manipulate(now);
      });

      {
        bool pause_manipulation = false;

        std::ifstream ifs(test["input_event_queue"].get<std::string>());
        REQUIRE(ifs);
        for (const auto& j : nlohmann::json::parse(ifs)) {
          if (auto s = json_utility::find_optional<std::string>(j, "action")) {
            if (*s == "invalidate_manipulators") {
              connector.invalidate_manipulators();
            } else if (*s == "invoke_manipulator_timer") {
              absolute_time time_stamp(0);
              if (auto t = json_utility::find_optional<uint64_t>(j, "time_stamp")) {
                time_stamp = absolute_time(*t);
              }
              manipulator_dispatcher->enqueue(
                  manipulator_object_id,
                  [&] {
                    manipulator_timer->async_invoke(time_stamp);
                  });
              // Wait after `async_invoke` to trigger manipulator_timer.
              std::this_thread::sleep_for(std::chrono::milliseconds(100));
            } else if (*s == "manipulate") {
              absolute_time time_stamp(0);
              if (auto t = json_utility::find_optional<uint64_t>(j, "time_stamp")) {
                time_stamp = absolute_time(*t);
              }
              connector.manipulate(time_stamp);
            } else if (*s == "sleep_milliseconds") {
              std::chrono::milliseconds ms(0);
              if (auto t = json_utility::find_optional<uint64_t>(j, "ms")) {
                ms = std::chrono::milliseconds(*t);
              }
              std::this_thread::sleep_for(ms);
            }

          } else if (auto v = json_utility::find_optional<bool>(j, "pause_manipulation")) {
            pause_manipulation = *v;
            if (!pause_manipulation) {
              connector.manipulate(now);
            }

          } else {
            auto e = event_queue::queued_event::make_from_json(j);
            now = e.get_event_time_stamp().get_time_stamp();
            event_queues.front()->push_back_event(e);
            if (!pause_manipulation) {
              connector.manipulate(now);
            }
          }
        }
      }

      std::this_thread::sleep_for(std::chrono::milliseconds(100));

      if (auto s = json_utility::find_optional<std::string>(test, "expected_event_queue")) {
        if (overwrite_expected_results) {
          std::ofstream ofs(*s);
          REQUIRE(ofs);
          ofs << nlohmann::json(event_queues.back()->get_events()).dump(4) << std::endl;
        }

        std::ifstream ifs(*s);
        REQUIRE(ifs);
        auto expected = nlohmann::json::parse(ifs);

        REQUIRE(event_queues.front()->get_events().empty());
        REQUIRE(nlohmann::json(event_queues.back()->get_events()).dump() == expected.dump());

      } else if (auto s = json_utility::find_optional<std::string>(test, "expected_post_event_to_virtual_devices_queue")) {
        if (overwrite_expected_results) {
          std::ofstream ofs(*s);
          REQUIRE(ofs);
          ofs << nlohmann::json(post_event_to_virtual_devices_manipulator->get_queue().get_events()).dump(4) << std::endl;
        }

        std::ifstream ifs(*s);
        REQUIRE(ifs);
        auto expected = nlohmann::json::parse(ifs);

        REQUIRE(post_event_to_virtual_devices_manipulator);
        REQUIRE(nlohmann::json(post_event_to_virtual_devices_manipulator->get_queue().get_events()).dump() == expected.dump());

      } else {
        logger::get_logger().error("There are not expected results.");
        REQUIRE(false);
      }

      input_event_arrived_connection.disconnect();

      manipulator_dispatcher->detach(manipulator_object_id);
      manipulator_timer->detach(manipulator_object_id);

      manipulator_managers.clear();
      post_event_to_virtual_devices_manipulator = nullptr;

      manipulator_dispatcher = nullptr;
      manipulator_timer = nullptr;
    }

    logger::get_logger().info("krbn::unit_testing::manipulator_helper::run_tests finished");
  }
};
} // namespace unit_testing
} // namespace krbn
<|endoftext|>