text:
static void test_loops(void);

static void test_comment(void);

static void test_function_calls(void);

static void test_match_cases(void);

static void test_comparison(void);

static void test_assignments(void);

static void test_lambdas(void);

static void test_new_lines(void);

static void test_successful_parse_impl(expression const expected, unicode_string const input, bool const is_statement,
                                       expression_pool *const pool)
{
    test_parser_user user = {{input.data, input.length, source_location_create(0, 0)}, NULL, 0};
    expression_parser parser = expression_parser_create(&user.base, handle_error, &user, pool);
    expression_parser_result result = parse_expression(&parser, 0, is_statement);
    REQUIRE(result.is_success);
    REQUIRE(user.base.remaining_size == 0);
    REQUIRE(expression_equals(&expected, &result.success));
    REQUIRE(!expression_parser_has_remaining_non_empty_tokens(&parser));
    expression_parser_free(parser);
    expression_free(result.success);
    unicode_string_free(&input);
}

static void test_save_expression_roundtrip(expression const tree, bool const is_statement, expression_pool *const pool)
{
    memory_writer buffer = {NULL, 0, 0};
    whitespace_state const whitespace = {0, false};
    REQUIRE(success_yes == save_expression(memory_writer_erase(&buffer), &tree, whitespace));
    test_successful_parse_impl(tree, unicode_string_from_range(buffer.data, buffer.used), is_statement, pool);
    memory_writer_free(&buffer);
}

static void test_successful_parse(expression const expected, unicode_string const input, bool const is_statement,
                                  expression_pool *const pool)
{
    test_successful_parse_impl(expected, input, is_statement, pool);
    test_save_expression_roundtrip(expected, is_statement, pool);
    expression_free(expected);
}

void test_parse_expression_success(void)
{
    expression_pool pool = expression_pool_create();

    test_successful_parse(expression_from_break(break_expression_create(source_location_create(0, 0), NULL)),
                          unicode_string_from_c_str("break"), true, &pool);

    test_successful_parse(
        expression_from_return(expression_allocate(expression_from_integer_literal(integer_literal_expression_create(
                                                       integer_create(0, 123), source_location_create(0, 7))),
                                                   &pool)),
        unicode_string_from_c_str("return 123"), true, &pool);

    test_successful_parse(expression_from_return(expression_allocate(
                              expression_from_call(call_create(
                                  expression_allocate(expression_from_identifier(identifier_expression_create(
                                                          unicode_view_from_c_str("f"), source_location_create(0, 7))),
                                                      &pool),
                                  tuple_create(NULL, 0, source_location_create(0, 0)), source_location_create(0, 9))),
                              &pool)),
                          unicode_string_from_c_str("return f()"), true, &pool);

    test_successful_parse(expression_from_identifier(
                              identifier_expression_create(unicode_view_from_c_str("a"), source_location_create(0, 0))),
                          unicode_string_from_c_str("a"), false, &pool);

    test_successful_parse(expression_from_integer_literal(
                              integer_literal_expression_create(integer_create(0, 123), source_location_create(0, 0))),
                          unicode_string_from_c_str("123"), false, &pool);

    test_successful_parse(expression_from_string(string_expression_create(
                              unicode_view_from_c_str("\"test\""), source_location_create(0, 0))),
                          unicode_string_from_c_str("\"test\""), false, &pool);

    test_successful_parse(expression_from_not(not_expression_create(
                              expression_allocate(expression_from_integer_literal(integer_literal_expression_create(
                                                      integer_create(0, 1), source_location_create(0, 1))),
                                                  &pool))),
                          unicode_string_from_c_str("!1"), true, &pool);

    test_successful_parse(expression_from_interface(interface_expression_create(
                              generic_parameter_list_create(NULL, 0), source_location_create(0, 0), NULL, 0)),
                          unicode_string_from_c_str("interface"), false, &pool);

    {
        interface_expression_method *const methods = allocate_array(1, sizeof(*methods));
        methods[0] = interface_expression_method_create(
            identifier_expression_create(unicode_view_from_c_str("method"), source_location_create(1, 4)),
            function_header_tree_create(
                NULL, 0,
                expression_allocate(expression_from_identifier(identifier_expression_create(
                                        unicode_view_from_c_str("return_type"), source_location_create(1, 14))),
                                    &pool)));
        test_successful_parse(expression_from_interface(interface_expression_create(
                                  generic_parameter_list_create(NULL, 0), source_location_create(0, 0), methods, 1)),
                              unicode_string_from_c_str("interface\n"
                                                        "    method(): return_type"),
                              false, &pool);
    }

    {
        interface_expression_method *const methods = allocate_array(2, sizeof(*methods));
        methods[0] = interface_expression_method_create(
            identifier_expression_create(unicode_view_from_c_str("a"), source_location_create(1, 4)),
            function_header_tree_create(
                NULL, 0, expression_allocate(expression_from_identifier(identifier_expression_create(
                                                 unicode_view_from_c_str("c"), source_location_create(1, 9))),
                                             &pool)));
        methods[1] = interface_expression_method_create(
            identifier_expression_create(unicode_view_from_c_str("b"), source_location_create(2, 4)),
            function_header_tree_create(
                NULL, 0, expression_allocate(expression_from_identifier(identifier_expression_create(
                                                 unicode_view_from_c_str("d"), source_location_create(2, 9))),
                                             &pool)));
        test_successful_parse(expression_from_interface(interface_expression_create(
                                  generic_parameter_list_create(NULL, 0), source_location_create(0, 0), methods, 2)),
                              unicode_string_from_c_str("interface\n"
                                                        "    a(): c\n"
                                                        "    b(): d"),
                              false, &pool);
    }

    test_successful_parse(expression_from_struct(struct_expression_create(
                              generic_parameter_list_create(NULL, 0), source_location_create(0, 0), NULL, 0)),
                          unicode_string_from_c_str("struct"), false, &pool);

    {
        struct_expression_element *const elements = allocate_array(1, sizeof(*elements));
        elements[0] = struct_expression_element_create(
            identifier_expression_create(unicode_view_from_c_str("a"), source_location_create(1, 4)),
            expression_from_identifier(
                identifier_expression_create(unicode_view_from_c_str("c"), source_location_create(1, 7))));
        test_successful_parse(expression_from_struct(struct_expression_create(
                                  generic_parameter_list_create(NULL, 0), source_location_create(0, 0), elements, 1)),
                              unicode_string_from_c_str("struct\n"
                                                        "    a: c"),
                              false, &pool);
    }

    {
        struct_expression_element *const elements = allocate_array(2, sizeof(*elements));
        elements[0] = struct_expression_element_create(
            identifier_expression_create(unicode_view_from_c_str("a"), source_location_create(1, 4)),
            expression_from_identifier(
                identifier_expression_create(unicode_view_from_c_str("c"), source_location_create(1, 7))));
        elements[1] = struct_expression_element_create(
            identifier_expression_create(unicode_view_from_c_str("b"), source_location_create(2, 4)),
            expression_from_identifier(
                identifier_expression_create(unicode_view_from_c_str("d"), source_location_create(2, 7))));
        test_successful_parse(expression_from_struct(struct_expression_create(
                                  generic_parameter_list_create(NULL, 0), source_location_create(0, 0), elements, 2)),
                              unicode_string_from_c_str("struct\n"
                                                        "    a: c\n"
                                                        "    b: d"),
                              false, &pool);
    }

    {
        unicode_view *const parameters = allocate_array(1, sizeof(*parameters));
        parameters[0] = unicode_view_from_c_str("a");
        test_successful_parse(expression_from_enum(enum_expression_create(
                                  source_location_create(0, 0), generic_parameter_list_create(parameters, 1), NULL, 0)),
                              unicode_string_from_c_str("enum[a]"), false, &pool);
    }

    {
        unicode_view *const parameters = allocate_array(2, sizeof(*parameters));
        parameters[0] = unicode_view_from_c_str("a");
        parameters[1] = unicode_view_from_c_str("b");
        test_successful_parse(expression_from_enum(enum_expression_create(
                                  source_location_create(0, 0), generic_parameter_list_create(parameters, 2), NULL, 0)),
                              unicode_string_from_c_str("enum[a, b]"), false, &pool);
    }

    {
        expression *const arguments = allocate_array(1, sizeof(*arguments));
        arguments[0] = expression_from_identifier(
            identifier_expression_create(unicode_view_from_c_str("a"), source_location_create(0, 2)));
        test_successful_parse(expression_from_generic_instantiation(generic_instantiation_expression_create(
                                  expression_allocate(expression_from_identifier(identifier_expression_create(
                                                          unicode_view_from_c_str("x"), source_location_create(0, 0))),
                                                      &pool),
                                  arguments, 1)),
                              unicode_string_from_c_str("x[a]"), false, &pool);
    }

    {
        expression *const arguments = allocate_array(2, sizeof(*arguments));
        arguments[0] = expression_from_identifier(
            identifier_expression_create(unicode_view_from_c_str("a"), source_location_create(0, 2)));
        arguments[1] = expression_from_identifier(
            identifier_expression_create(unicode_view_from_c_str("b"), source_location_create(0, 5)));
        test_successful_parse(expression_from_generic_instantiation(generic_instantiation_expression_create(
                                  expression_allocate(expression_from_identifier(identifier_expression_create(
                                                          unicode_view_from_c_str("x"), source_location_create(0, 0))),
                                                      &pool),
                                  arguments, 2)),
                              unicode_string_from_c_str("x[a, b]"), false, &pool);
    }

    expression_pool_free(pool);
    test_function_calls();
    test_comment();
    test_loops();
    test_comparison();
    test_assignments();
    test_match_cases();
    test_lambdas();
    test_new_lines();
}

static void test_new_lines(void)
{
    expression_pool pool = expression_pool_create();
    // Empty line with just whitespace
    {
        unicode_string const input = unicode_string_from_c_str("  ");
        test_parser_user user = {{input.data, input.length, source_location_create(0, 0)}, NULL, 0};
        expression_parser parser = expression_parser_create(&user.base, handle_error, &user, &pool);

        sequence actual = parse_program(&parser);
        REQUIRE(actual.length == 0);

        expression_parser_free(parser);
        sequence_free(&actual);
        unicode_string_free(&input);
    }

    // Empty line with just indentation
    {
        unicode_string const input = unicode_string_from_c_str("    ");
        test_parser_user user = {{input.data, input.length, source_location_create(0, 0)}, NULL, 0};
        expression_parser parser = expression_parser_create(&user.base, handle_error, &user, &pool);

        sequence actual = parse_program(&parser);
        REQUIRE(actual.length == 0);

        expression_parser_free(parser);
        sequence_free(&actual);
        unicode_string_free(&input);
    }

    // One trailing whitespace at the end
    {
        expression *left = expression_pool_allocate(&pool);
        *left = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 200), source_location_create(0, 0)));

        expression *right = expression_pool_allocate(&pool);
        *right = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 2), source_location_create(0, 7)));

        expression unequals_expression =
            expression_from_binary_operator(binary_operator_expression_create(left, right, not_equals));

        unicode_string const input = unicode_string_from_c_str("200 != 2 ");
        test_parser_user user = {{input.data, input.length, source_location_create(0, 0)}, NULL, 0};
        expression_parser parser = expression_parser_create(&user.base, handle_error, &user, &pool);

        sequence actual = parse_program(&parser);
        REQUIRE(actual.length == 1);
        REQUIRE(expression_equals(&actual.elements[0], &unequals_expression));

        expression_parser_free(parser);
        expression_free(unequals_expression);
        sequence_free(&actual);
        unicode_string_free(&input);
    }

    // An empty line within a loop
    {
        unicode_string const input = unicode_string_from_c_str("loop\n"
                                                               "    \n"
                                                               "    break");
        expression *elements = allocate_array(1, sizeof(*elements));
        elements[0] = expression_from_break(break_expression_create(source_location_create(2, 4), NULL));
        expression loop_expression = expression_from_loop(sequence_create(elements, 1, source_location_create(1, 0)));

        test_parser_user user = {{input.data, input.length, source_location_create(0, 0)}, NULL, 0};
        expression_parser parser = expression_parser_create(&user.base, handle_error, &user, &pool);

        sequence actual = parse_program(&parser);
        REQUIRE(actual.length == 1);
        REQUIRE(expression_equals(&actual.elements[0], &loop_expression));

        expression_parser_free(parser);
        expression_free(loop_expression);
        sequence_free(&actual);
        unicode_string_free(&input);
    }
    expression_pool_free(pool);
}

static void test_lambdas()
{
    expression_pool pool = expression_pool_create();

    // Lambda with direct return value
    test_successful_parse(expression_from_lambda(lambda_create(
                              generic_parameter_list_create(NULL, 0), function_header_tree_create(NULL, 0, NULL),
                              expression_allocate(expression_from_integer_literal(integer_literal_expression_create(
                                                      integer_create(0, 1), source_location_create(0, 3))),
                                                  &pool),
                              source_location_create(0, 0))),
                          unicode_string_from_c_str("() 1"), false, &pool);

    // Lambda with return type and implicit return
    {
        expression *result_expression = expression_pool_allocate(&pool);
        *result_expression = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 1), source_location_create(0, 4)));

        expression *const elements = allocate_array(1, sizeof(*elements));
        elements[0] = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 1), source_location_create(1, 4)));
        test_successful_parse(
            expression_from_lambda(lambda_create(
                generic_parameter_list_create(NULL, 0), function_header_tree_create(NULL, 0, result_expression),
                expression_allocate(
                    expression_from_sequence(sequence_create(elements, 1, source_location_create(1, 0))), &pool),
                source_location_create(0, 0))),
            unicode_string_from_c_str("(): 1\n"
                                      "    1"),
            false, &pool);
    }

    // Lambda returning a lamda
    test_successful_parse(
        expression_from_lambda(
            lambda_create(generic_parameter_list_create(NULL, 0), function_header_tree_create(NULL, 0, NULL),
                          expression_allocate(
                              expression_from_lambda(lambda_create(
                                  generic_parameter_list_create(NULL, 0), function_header_tree_create(NULL, 0, NULL),
                                  expression_allocate(expression_from_integer_literal(integer_literal_expression_create(
                                                          integer_create(0, 1), source_location_create(0, 6))),
                                                      &pool),
                                  source_location_create(0, 3))),
                              &pool),
                          source_location_create(0, 0))),
        unicode_string_from_c_str("() () 1"), false, &pool);

    // Lambda without a return type
    {
        expression *const elements = allocate_array(1, sizeof(*elements));
        elements[0] = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 1), source_location_create(1, 4)));
        test_successful_parse(
            expression_from_lambda(lambda_create(
                generic_parameter_list_create(NULL, 0), function_header_tree_create(NULL, 0, NULL),
                expression_allocate(
                    expression_from_sequence(sequence_create(elements, 1, source_location_create(1, 0))), &pool),
                source_location_create(0, 0))),
            unicode_string_from_c_str("()\n"
                                      "    1"),
            false, &pool);
    }
    // Lamda with a typed parameter and no return type
    {
        expression *const elements = allocate_array(1, sizeof(*elements));
        elements[0] = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 1), source_location_create(1, 4)));
        parameter *const parameters = allocate_array(1, sizeof(*parameters));
        parameters[0] =
            parameter_create(identifier_expression_create(unicode_view_from_c_str("a"), source_location_create(0, 1)),
                             expression_allocate(expression_from_identifier(identifier_expression_create(
                                                     unicode_view_from_c_str("type"), source_location_create(0, 4))),
                                                 &pool));
        test_successful_parse(
            expression_from_lambda(lambda_create(
                generic_parameter_list_create(NULL, 0), function_header_tree_create(parameters, 1, NULL),
                expression_allocate(
                    expression_from_sequence(sequence_create(elements, 1, source_location_create(1, 0))), &pool),
                source_location_create(0, 0))),
            unicode_string_from_c_str("(a: type)\n"
                                      "    1"),
            false, &pool);
    }

    // Lambda with two paramaters
    {
        expression *const elements = allocate_array(1, sizeof(*elements));
        elements[0] = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 1), source_location_create(1, 4)));
        parameter *const parameters = allocate_array(2, sizeof(*parameters));
        parameters[0] =
            parameter_create(identifier_expression_create(unicode_view_from_c_str("a"), source_location_create(0, 1)),
                             expression_allocate(expression_from_identifier(identifier_expression_create(
                                                     unicode_view_from_c_str("b"), source_location_create(0, 4))),
                                                 &pool));
        parameters[1] =
            parameter_create(identifier_expression_create(unicode_view_from_c_str("c"), source_location_create(0, 7)),
                             expression_allocate(expression_from_identifier(identifier_expression_create(
                                                     unicode_view_from_c_str("d"), source_location_create(0, 10))),
                                                 &pool));
        test_successful_parse(
            expression_from_lambda(lambda_create(
                generic_parameter_list_create(NULL, 0), function_header_tree_create(parameters, 2, NULL),
                expression_allocate(
                    expression_from_sequence(sequence_create(elements, 1, source_location_create(1, 0))), &pool),
                source_location_create(0, 0))),
            unicode_string_from_c_str("(a: b, c: d)\n"
                                      "    1"),
            false, &pool);
    }

    expression_pool_free(pool);
}

static void test_comparison(void)
{
    expression_pool pool = expression_pool_create();
    {
        expression *left = expression_pool_allocate(&pool);
        *left = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 200), source_location_create(0, 0)));

        expression *right = expression_pool_allocate(&pool);
        *right = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 2), source_location_create(0, 7)));
        test_successful_parse(
            expression_from_binary_operator(binary_operator_expression_create(left, right, not_equals)),
            unicode_string_from_c_str("200 != 2"), true, &pool);
    }

    {
        expression *left = expression_pool_allocate(&pool);
        *left = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 200), source_location_create(0, 0)));

        expression *right = expression_pool_allocate(&pool);
        *right = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 2), source_location_create(0, 7)));
        test_successful_parse(
            expression_from_binary_operator(binary_operator_expression_create(left, right, less_than_or_equals)),
            unicode_string_from_c_str("200 <= 2"), true, &pool);
    }
    {
        expression *left = expression_pool_allocate(&pool);
        *left = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 200), source_location_create(0, 0)));

        expression *right = expression_pool_allocate(&pool);
        *right = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 2), source_location_create(0, 7)));
        test_successful_parse(
            expression_from_binary_operator(binary_operator_expression_create(left, right, greater_than_or_equals)),
            unicode_string_from_c_str("200 >= 2"), true, &pool);
    }
    {
        expression *left = expression_pool_allocate(&pool);
        *left = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 200), source_location_create(0, 0)));

        expression *right = expression_pool_allocate(&pool);
        *right = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 2), source_location_create(0, 7)));
        test_successful_parse(expression_from_binary_operator(binary_operator_expression_create(left, right, equals)),
                              unicode_string_from_c_str("200 == 2"), true, &pool);
    }
    {
        expression *left = expression_pool_allocate(&pool);
        *left = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 200), source_location_create(0, 0)));

        expression *right = expression_pool_allocate(&pool);
        *right = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 2), source_location_create(0, 6)));
        test_successful_parse(
            expression_from_binary_operator(binary_operator_expression_create(left, right, less_than)),
            unicode_string_from_c_str("200 < 2"), true, &pool);
    }
    {
        expression *left = expression_pool_allocate(&pool);
        *left = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 200), source_location_create(0, 0)));

        expression *right = expression_pool_allocate(&pool);
        *right = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 2), source_location_create(0, 6)));
        test_successful_parse(
            expression_from_binary_operator(binary_operator_expression_create(left, right, greater_than)),
            unicode_string_from_c_str("200 > 2"), true, &pool);
    }
    expression_pool_free(pool);
}

static void test_assignments(void)
{
    expression_pool pool = expression_pool_create();
    test_successful_parse(expression_from_binary_operator(binary_operator_expression_create(
                              expression_allocate(expression_from_identifier(identifier_expression_create(
                                                      unicode_view_from_c_str("a"), source_location_create(0, 0))),
                                                  &pool),
                              expression_allocate(expression_from_integer_literal(integer_literal_expression_create(
                                                      integer_create(0, 1), source_location_create(0, 5))),
                                                  &pool),
                              equals)),
                          unicode_string_from_c_str("a == 1"), true, &pool);

    test_successful_parse(
        expression_from_declare(
            declare_create(identifier_expression_create(unicode_view_from_c_str("a"), source_location_create(0, 4)),
                           NULL, expression_allocate(expression_from_integer_literal(integer_literal_expression_create(
                                                         integer_create(0, 1), source_location_create(0, 8))),
                                                     &pool))),
        unicode_string_from_c_str("let a = 1"), true, &pool);

    test_successful_parse(expression_from_declare(declare_create(
                              identifier_expression_create(unicode_view_from_c_str("a"), source_location_create(0, 4)),
                              expression_allocate(expression_from_identifier(identifier_expression_create(
                                                      unicode_view_from_c_str("int"), source_location_create(0, 8))),
                                                  &pool),
                              expression_allocate(expression_from_integer_literal(integer_literal_expression_create(
                                                      integer_create(0, 1), source_location_create(0, 14))),
                                                  &pool))),
                          unicode_string_from_c_str("let a : int = 1"), true, &pool);
    expression_pool_free(pool);
}

static void test_match_cases(void)
{
    expression_pool pool = expression_pool_create();
    {
        match_case *const cases = allocate_array(1, sizeof(*cases));
        cases[0] =
            match_case_create(expression_allocate(expression_from_integer_literal(integer_literal_expression_create(
                                                      integer_create(0, 1), source_location_create(1, 9))),
                                                  &pool),
                              expression_allocate(expression_from_integer_literal(integer_literal_expression_create(
                                                      integer_create(0, 2), source_location_create(1, 12))),
                                                  &pool));
        test_successful_parse(expression_from_match(match_create(
                                  source_location_create(0, 0),
                                  expression_allocate(expression_from_identifier(identifier_expression_create(
                                                          unicode_view_from_c_str("a"), source_location_create(0, 6))),
                                                      &pool),
                                  cases, 1)),
                              unicode_string_from_c_str("match a\n"
                                                        "    case 1: 2\n"),
                              false, &pool);
    }

    {
        match_case *const cases = allocate_array(2, sizeof(*cases));
        cases[0] =
            match_case_create(expression_allocate(expression_from_integer_literal(integer_literal_expression_create(
                                                      integer_create(0, 1), source_location_create(1, 9))),
                                                  &pool),
                              expression_allocate(expression_from_integer_literal(integer_literal_expression_create(
                                                      integer_create(0, 2), source_location_create(1, 12))),
                                                  &pool));
        cases[1] =
            match_case_create(expression_allocate(expression_from_integer_literal(integer_literal_expression_create(
                                                      integer_create(0, 3), source_location_create(2, 9))),
                                                  &pool),
                              expression_allocate(expression_from_integer_literal(integer_literal_expression_create(
                                                      integer_create(0, 4), source_location_create(2, 12))),
                                                  &pool));
        test_successful_parse(expression_from_match(match_create(
                                  source_location_create(0, 0),
                                  expression_allocate(expression_from_identifier(identifier_expression_create(
                                                          unicode_view_from_c_str("a"), source_location_create(0, 6))),
                                                      &pool),
                                  cases, 2)),
                              unicode_string_from_c_str("match a\n"
                                                        "    case 1: 2\n"
                                                        "    case 3: 4\n"),
                              false, &pool);
    }

    {
        match_case *const cases = allocate_array(2, sizeof(*cases));
        expression *case_0 = allocate_array(1, sizeof(*case_0));
        case_0[0] = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 2), source_location_create(2, 8)));
        cases[0] = match_case_create(
            expression_allocate(expression_from_integer_literal(integer_literal_expression_create(
                                    integer_create(0, 1), source_location_create(1, 9))),
                                &pool),
            expression_allocate(
                expression_from_sequence(sequence_create(case_0, 1, source_location_create(2, 0))), &pool));
        cases[1] =
            match_case_create(expression_allocate(expression_from_integer_literal(integer_literal_expression_create(
                                                      integer_create(0, 3), source_location_create(3, 9))),
                                                  &pool),
                              expression_allocate(expression_from_integer_literal(integer_literal_expression_create(
                                                      integer_create(0, 4), source_location_create(3, 12))),
                                                  &pool));
        test_successful_parse(expression_from_match(match_create(
                                  source_location_create(0, 0),
                                  expression_allocate(expression_from_identifier(identifier_expression_create(
                                                          unicode_view_from_c_str("a"), source_location_create(0, 6))),
                                                      &pool),
                                  cases, 2)),
                              unicode_string_from_c_str("match a\n"
                                                        "    case 1:\n"
                                                        "        2\n"
                                                        "    case 3: 4\n"),
                              false, &pool);
    }
    expression_pool_free(pool);
}

static void test_function_calls(void)
{
    expression_pool pool = expression_pool_create();
    {
        tuple const arguments = tuple_create(NULL, 0, source_location_create(0, 0));
        test_successful_parse(expression_from_call(call_create(
                                  expression_allocate(expression_from_identifier(identifier_expression_create(
                                                          unicode_view_from_c_str("f"), source_location_create(0, 0))),
                                                      &pool),
                                  arguments, source_location_create(0, 2))),
                              unicode_string_from_c_str("f()"), false, &pool);
    }
    {
        tuple const arguments = tuple_create(NULL, 0, source_location_create(0, 0));
        test_successful_parse(
            expression_from_call(call_create(
                expression_allocate(
                    expression_from_call(call_create(
                        expression_allocate(expression_from_identifier(identifier_expression_create(
                                                unicode_view_from_c_str("f"), source_location_create(0, 0))),
                                            &pool),
                        arguments, source_location_create(0, 2))),
                    &pool),
                arguments, source_location_create(0, 4))),
            unicode_string_from_c_str("f()()"), false, &pool);
    }
    {
        expression *arguments = allocate_array(1, sizeof(*arguments));
        arguments[0] = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 1), source_location_create(0, 2)));
        tuple const arguments_tuple = tuple_create(arguments, 1, source_location_create(0, 0));
        test_successful_parse(expression_from_call(call_create(
                                  expression_allocate(expression_from_identifier(identifier_expression_create(
                                                          unicode_view_from_c_str("f"), source_location_create(0, 0))),
                                                      &pool),
                                  arguments_tuple, source_location_create(0, 3))),
                              unicode_string_from_c_str("f(1)"), false, &pool);
    }
    {
        expression *arguments = allocate_array(2, sizeof(*arguments));
        arguments[0] = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 1), source_location_create(0, 2)));
        arguments[1] = expression_from_integer_literal(
            integer_literal_expression_create(integer_create(0, 2), source_location_create(0, 5)));
        tuple const arguments_tuple = tuple_create(arguments, 2, source_location_create(0, 0));
        test_successful_parse(expression_from_call(call_create(
                                  expression_allocate(expression_from_identifier(identifier_expression_create(
                                                          unicode_view_from_c_str("f"), source_location_create(0, 0))),
                                                      &pool),
                                  arguments_tuple, source_location_create(0, 6))),
                              unicode_string_from_c_str("f(1, 2)"), false, &pool);
    }
    expression_pool_free(pool);
}

static void test_comment(void)
{
    expression_pool pool = expression_pool_create();
    {
        expression const expr = expression_from_comment(
            comment_expression_create(unicode_string_from_c_str("Testing the comments"), source_location_create(0, 0)));
        test_successful_parse(expr, unicode_string_from_c_str("//Testing the comments"), false, &pool);
    }
    {
        expression *elements = allocate_array(2, sizeof(*elements));
        elements[0] = expression_from_comment(
            comment_expression_create(unicode_string_from_c_str("Testing the comments"), source_location_create(1, 4)));
        elements[1] = expression_from_break(break_expression_create(source_location_create(2, 4), NULL));
        test_successful_parse(expression_from_loop(sequence_create(elements, 2, source_location_create(1, 0))),
                              unicode_string_from_c_str("loop\n"
                                                        "    //Testing the comments\n"
                                                        "    break"),
                              false, &pool);
    }
    expression_pool_free(pool);
}

static void test_loops(void)
{
    expression_pool pool = expression_pool_create();
    {
        expression *elements = allocate_array(1, sizeof(*elements));
        elements[0] = expression_from_break(break_expression_create(source_location_create(1, 4), NULL));
        test_successful_parse(expression_from_loop(sequence_create(elements, 1, source_location_create(1, 0))),
                              unicode_string_from_c_str("loop\n"
                                                        "    break"),
                              false, &pool);
    }
    {
        expression *elements = allocate_array(2, sizeof(*elements));
        elements[0] = expression_from_identifier(
            identifier_expression_create(unicode_view_from_c_str("f"), source_location_create(1, 4)));
        elements[1] = expression_from_break(break_expression_create(source_location_create(2, 4), NULL));
        test_successful_parse(expression_from_loop(sequence_create(elements, 2, source_location_create(1, 0))),
                              unicode_string_from_c_str("loop\n"
                                                        "    f\n"
                                                        "    break"),
                              false, &pool);
    }
    {
        expression *elements = allocate_array(2, sizeof(*elements));
        elements[0] = expression_from_identifier(
            identifier_expression_create(unicode_view_from_c_str("f"), source_location_create(1, 4)));
        elements[1] = expression_from_break(break_expression_create(source_location_create(2, 4), NULL));
        test_successful_parse(expression_from_loop(sequence_create(elements, 2, source_location_create(1, 0))),
                              unicode_string_from_c_str("loop\n"
                                                        "    f\n"
                                                        "    break\n"),
                              false, &pool);
    }
    {
        expression *inner_loop = allocate_array(1, sizeof(*inner_loop));
        inner_loop[0] = expression_from_break(break_expression_create(source_location_create(2, 8), NULL));
        expression *outer_loop = allocate_array(1, sizeof(*outer_loop));
        outer_loop[0] = expression_from_loop(sequence_create(inner_loop, 1, source_location_create(1, 0)));
        test_successful_parse(expression_from_loop(sequence_create(outer_loop, 1, source_location_create(2, 0))),
                              unicode_string_from_c_str("loop\n"
                                                        "    loop\n"
                                                        "        break\n"),
                              false, &pool);
    }
    {
        expression *inner_loop = allocate_array(1, sizeof(*inner_loop));
        inner_loop[0] = expression_from_break(break_expression_create(source_location_create(2, 8), NULL));
        expression *outer_loop = allocate_array(2, sizeof(*outer_loop));
        outer_loop[0] = expression_from_loop(sequence_create(inner_loop, 1, source_location_create(1, 0)));
        outer_loop[1] = expression_from_break(break_expression_create(source_location_create(3, 4), NULL));
        test_successful_parse(expression_from_loop(sequence_create(outer_loop, 2, source_location_create(2, 0))),
                              unicode_string_from_c_str("loop\n"
                                                        "    loop\n"
                                                        "        break\n"
                                                        "    break\n"),
                              false, &pool);
    }

    expression_pool_free(pool);
}


text:
/**
 * @fileoverview Abstraction of JavaScript source code.
 * @author Nicholas C. Zakas
 */
"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

var fs = require("fs"),
    path = require("path"),
    assert = require("chai").assert,
    espree = require("espree"),
    sinon = require("sinon"),
    leche = require("leche"),
    eslint = require("../../../lib/eslint"),
    SourceCode = require("../../../lib/util/source-code");

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

var DEFAULT_CONFIG = {
    ecmaVersion: 6,
    comment: true,
    tokens: true,
    range: true,
    loc: true
};

var AST = espree.parse("let foo = bar;", DEFAULT_CONFIG),
    TEST_CODE = "var answer = 6 * 7;";

//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------

describe("SourceCode", function() {

    describe("new SourceCode()", function() {

        it("should create a new instance when called with valid data", function() {
            var ast = { comments: [], tokens: [], loc: {}, range: [] };
            var sourceCode = new SourceCode("foo;", ast);

            assert.isObject(sourceCode);
            assert.equal(sourceCode.text, "foo;");
            assert.equal(sourceCode.ast, ast);
        });

        it("should split text into lines when called with valid data", function() {
            var ast = { comments: [], tokens: [], loc: {}, range: [] };
            var sourceCode = new SourceCode("foo;\nbar;", ast);

            assert.isObject(sourceCode);
            assert.equal(sourceCode.lines.length, 2);
            assert.equal(sourceCode.lines[0], "foo;");
            assert.equal(sourceCode.lines[1], "bar;");
        });

        /* eslint-disable no-new */

        it("should throw an error when called with an AST that's missing tokens", function() {

            assert.throws(function() {
                new SourceCode("foo;", { comments: [], loc: {}, range: [] });
            }, /missing the tokens array/);

        });

        it("should throw an error when called with an AST that's missing comments", function() {

            assert.throws(function() {
                new SourceCode("foo;", { tokens: [], loc: {}, range: [] });
            }, /missing the comments array/);

        });

        it("should throw an error when called with an AST that's missing comments", function() {

            assert.throws(function() {
                new SourceCode("foo;", { comments: [], tokens: [], range: [] });
            }, /missing location information/);

        });

        it("should throw an error when called with an AST that's missing comments", function() {

            assert.throws(function() {
                new SourceCode("foo;", { comments: [], tokens: [], loc: {} });
            }, /missing range information/);
        });

        it("should store all tokens and comments sorted by range", function() {
            var comments = [
                { range: [0, 2] },
                { range: [10, 12] }
            ];
            var tokens = [
                { range: [3, 8] },
                { range: [8, 10] },
                { range: [12, 20] }
            ];
            var sourceCode = new SourceCode("", { comments: comments, tokens: tokens, loc: {}, range: [] });

            var actual = sourceCode.tokensAndComments;
            var expected = [comments[0], tokens[0], tokens[1], comments[1], tokens[2]];

            assert.deepEqual(actual, expected);
        });

        describe("if a text has BOM,", function() {
            var sourceCode;

            beforeEach(function() {
                var ast = { comments: [], tokens: [], loc: {}, range: [] };

                sourceCode = new SourceCode("\uFEFFconsole.log('hello');", ast);
            });

            it("should has true at `hasBOM` property.", function() {
                assert.equal(sourceCode.hasBOM, true);
            });

            it("should not has BOM in `text` property.", function() {
                assert.equal(sourceCode.text, "console.log('hello');");
            });
        });

        describe("if a text doesn't have BOM,", function() {
            var sourceCode;

            beforeEach(function() {
                var ast = { comments: [], tokens: [], loc: {}, range: [] };

                sourceCode = new SourceCode("console.log('hello');", ast);
            });

            it("should has false at `hasBOM` property.", function() {
                assert.equal(sourceCode.hasBOM, false);
            });

            it("should not has BOM in `text` property.", function() {
                assert.equal(sourceCode.text, "console.log('hello');");
            });
        });

        describe("when it read a UTF-8 file (has BOM), SourceCode", function() {
            var UTF8_FILE = path.resolve(__dirname, "../../fixtures/utf8-bom.js");
            var text = fs.readFileSync(
                    UTF8_FILE,
                    "utf8"
                ).replace(/\r\n/g, "\n"); // <-- For autocrlf of "git for Windows"
            var sourceCode;

            beforeEach(function() {
                var ast = { comments: [], tokens: [], loc: {}, range: [] };

                sourceCode = new SourceCode(text, ast);
            });

            it("to be clear, check the file has UTF-8 BOM.", function() {
                var buffer = fs.readFileSync(UTF8_FILE);

                assert.equal(buffer[0], 0xEF);
                assert.equal(buffer[1], 0xBB);
                assert.equal(buffer[2], 0xBF);
            });

            it("should has true at `hasBOM` property.", function() {
                assert.equal(sourceCode.hasBOM, true);
            });

            it("should not has BOM in `text` property.", function() {
                assert.equal(
                    sourceCode.text,
                    "\"use strict\";\n\nconsole.log(\"This file has [0xEF, 0xBB, 0xBF] as BOM.\");\n");
            });
        });
    });

    describe("getJSDocComment()", function() {

        var sandbox = sinon.sandbox.create(),
            filename = "foo.js";

        beforeEach(function() {
            eslint.reset();
        });

        afterEach(function() {
            sandbox.verifyAndRestore();
        });

        it("should not take a JSDoc comment from a FunctionDeclaration parent node when the node is a FunctionExpression", function() {

            var code = [
                "/** Desc*/",
                "function Foo(){var t = function(){}}"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.equal(jsdoc, null);
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionExpression", spy);
            eslint.verify(code, { rules: {}}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");

        });

        it("should not take a JSDoc comment from a VariableDeclaration parent node when the node is a FunctionExpression inside a NewExpression", function() {

            var code = [
                "/** Desc*/",
                "var x = new Foo(function(){});"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.equal(jsdoc, null);
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionExpression", spy);
            eslint.verify(code, { rules: {}}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");

        });

        it("should not take a JSDoc comment from a FunctionExpression parent node when the node is a FunctionExpression", function() {

            var code = [
                "/** Desc*/",
                "var f = function(){var t = function(arg){}}"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                if (node.params.length === 1) {
                    var sourceCode = eslint.getSourceCode();
                    var jsdoc = sourceCode.getJSDocComment(node);

                    assert.equal(jsdoc, null);
                }
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionExpression", spy);
            eslint.verify(code, { rules: {}}, filename, true);
            assert.isTrue(spy.calledTwice, "Event handler should be called twice.");

        });

        it("should get JSDoc comment for FunctionExpression in a CallExpression", function() {
            var code = [
                "call(",
                "  /** Documentation. */",
                "  function(argName) {",
                "    return 'the return';",
                "  }",
                ");"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.equal(jsdoc.type, "Block");
                assert.equal(jsdoc.value, "* Documentation. ");
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionExpression", spy);
            eslint.verify(code, {rules: {}}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");
        });

        it("should get JSDoc comment for node when the node is a FunctionDeclaration", function() {

            var code = [
                "/** Desc*/",
                "function Foo(){}"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.equal(jsdoc.type, "Block");
                assert.equal(jsdoc.value, "* Desc");
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionDeclaration", spy);
            eslint.verify(code, { rules: {}}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");

        });

        it("should get JSDoc comment for node when the node is a FunctionDeclaration but its parent is an export", function() {

            var code = [
                "/** Desc*/",
                "export function Foo(){}"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.equal(jsdoc.type, "Block");
                assert.equal(jsdoc.value, "* Desc");
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionDeclaration", spy);
            eslint.verify(code, { parserOptions: { sourceType: "module" }, rules: {}}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");

        });

        it("should get JSDoc comment for node when the node is a FunctionDeclaration but not the first statement", function() {

            var code = [
                "'use strict';",
                "/** Desc*/",
                "function Foo(){}"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.equal(jsdoc.type, "Block");
                assert.equal(jsdoc.value, "* Desc");
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionDeclaration", spy);
            eslint.verify(code, { rules: {}}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");

        });

        it("should not get JSDoc comment for node when the node is a FunctionDeclaration inside of an IIFE without a JSDoc comment", function() {

            var code = [
                "/** Desc*/",
                "(function(){",
                "function Foo(){}",
                "}())"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.isNull(jsdoc);
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionDeclaration", spy);
            eslint.verify(code, { rules: {}}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");

        });

        it("should get JSDoc comment for node when the node is a FunctionDeclaration and there are multiple comments", function() {

            var code = [
                "/* Code is good */",
                "/** Desc*/",
                "function Foo(){}"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.equal(jsdoc.type, "Block");
                assert.equal(jsdoc.value, "* Desc");
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionDeclaration", spy);
            eslint.verify(code, { rules: {}}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");

        });

        it("should get JSDoc comment for node when the node is a FunctionDeclaration inside of an IIFE", function() {

            var code = [
                "/** Code is good */",
                "(function() {",
                "/** Desc*/",
                "function Foo(){}",
                "}())"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.equal(jsdoc.type, "Block");
                assert.equal(jsdoc.value, "* Desc");
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionDeclaration", spy);
            eslint.verify(code, { rules: {}}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");
        });

        it("should get JSDoc comment for node when the node is a FunctionExpression inside of an object literal", function() {

            var code = [
                "/** Code is good */",
                "var o = {",
                "/** Desc*/",
                "foo: function(){}",
                "};"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.equal(jsdoc.type, "Block");
                assert.equal(jsdoc.value, "* Desc");
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionExpression", spy);
            eslint.verify(code, { rules: {}}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");
        });

        it("should get JSDoc comment for node when the node is a ArrowFunctionExpression inside of an object literal", function() {

            var code = [
                "/** Code is good */",
                "var o = {",
                "/** Desc*/",
                "foo: () => {}",
                "};"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.equal(jsdoc.type, "Block");
                assert.equal(jsdoc.value, "* Desc");
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("ArrowFunctionExpression", spy);
            eslint.verify(code, { parserOptions: { ecmaVersion: 6 }, rules: {}}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");
        });

        it("should get JSDoc comment for node when the node is a FunctionExpression in an assignment", function() {

            var code = [
                "/** Code is good */",
                "/** Desc*/",
                "Foo.bar = function(){}"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.equal(jsdoc.type, "Block");
                assert.equal(jsdoc.value, "* Desc");
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionExpression", spy);
            eslint.verify(code, { rules: {}}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");
        });

        it("should get JSDoc comment for node when the node is a FunctionExpression in an assignment inside an IIFE", function() {

            var code = [
                "/** Code is good */",
                "(function iife() {",
                "/** Desc*/",
                "Foo.bar = function(){}",
                "}());"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                if (!node.id) {
                    var sourceCode = eslint.getSourceCode();
                    var jsdoc = sourceCode.getJSDocComment(node);

                    assert.equal(jsdoc.type, "Block");
                    assert.equal(jsdoc.value, "* Desc");
                }
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionExpression", spy);
            eslint.verify(code, { rules: {}}, filename, true);
            assert.isTrue(spy.calledTwice, "Event handler should be called.");
        });

        it("should not get JSDoc comment for node when the node is a FunctionExpression in an assignment inside an IIFE without a JSDoc comment", function() {

            var code = [
                "/** Code is good */",
                "(function iife() {",
                "//* whatever",
                "Foo.bar = function(){}",
                "}());"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                if (!node.id) {
                    var sourceCode = eslint.getSourceCode();
                    var jsdoc = sourceCode.getJSDocComment(node);

                    assert.isNull(jsdoc);
                }
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionExpression", spy);
            eslint.verify(code, { rules: {}}, filename, true);
            assert.isTrue(spy.calledTwice, "Event handler should be called.");
        });

        it("should not get JSDoc comment for node when the node is a FunctionExpression inside of a CallExpression", function() {

            var code = [
                "/** Code is good */",
                "module.exports = (function() {",
                "}());"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                if (!node.id) {
                    var sourceCode = eslint.getSourceCode();
                    var jsdoc = sourceCode.getJSDocComment(node);

                    assert.isNull(jsdoc);
                }
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionExpression", spy);
            eslint.verify(code, { rules: {}}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");
        });

        it("should not get JSDoc comment for node when the node is a FunctionExpression in an assignment inside an IIFE without a JSDoc comment", function() {

            var code = [
                "/**",
                " * Merges two objects together.",
                " * @param {Object} target of the cloning operation",
                " * @param {Object} [source] object",
                " * @returns {void}",
                " */",
                "exports.mixin = function(target, source) {",
                "    Object.keys(source).forEach(function forEach(key) {",
                "        target[key] = source[key];",
                "    });",
                "};"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                if (node.id) {
                    var sourceCode = eslint.getSourceCode();
                    var jsdoc = sourceCode.getJSDocComment(node);

                    assert.isNull(jsdoc);
                }
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionExpression", spy);
            eslint.verify(code, { rules: {}}, filename, true);
            assert.isTrue(spy.calledTwice, "Event handler should be called.");
        });

        it("should get JSDoc comment for node when the node is a ClassExpression", function() {

            var code = [
                "/** Merges two objects together.*/",
                "var A = class {",
                "};"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.equal(jsdoc.type, "Block");
                assert.equal(jsdoc.value, "* Merges two objects together.");
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("ClassExpression", spy);
            eslint.verify(code, { rules: {}, parserOptions: { ecmaVersion: 6 }}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");
        });

        it("should get JSDoc comment for node when the node is a ClassDeclaration", function() {

            var code = [
                "/** Merges two objects together.*/",
                "class A {",
                "};"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.equal(jsdoc.type, "Block");
                assert.equal(jsdoc.value, "* Merges two objects together.");
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("ClassDeclaration", spy);
            eslint.verify(code, { rules: {}, parserOptions: { ecmaVersion: 6 }}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");
        });

        it("should not get JSDoc comment for class method even if the class has jsdoc present", function() {

            var code = [
                "/** Merges two objects together.*/",
                "var A = class {",
                "    constructor(xs) {}",
                "};"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.isNull(jsdoc);
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionExpression", spy);
            eslint.verify(code, { rules: {}, parserOptions: { ecmaVersion: 6 }}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");
        });

        it("should get JSDoc comment for function expression even if function has blank lines on top", function() {

            var code = [
                "/** Merges two objects together.*/",
                "var A = ",
                " ",
                " ",
                " ",
                "     function() {",
                "};"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.equal(jsdoc.type, "Block");
                assert.equal(jsdoc.value, "* Merges two objects together.");
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionExpression", spy);
            eslint.verify(code, { rules: {}, parserOptions: { ecmaVersion: 6 }}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");
        });

        it("should not get JSDoc comment for function declaration when the function has blank lines on top", function() {

            var code = [
                "/** Merges two objects together.*/",
                " ",
                " ",
                " ",
                "function test() {",
                "};"
            ].join("\n");

            /**
             * Check jsdoc presence
             * @param {ASTNode} node not to check
             * @returns {void}
             * @private
             */
            function assertJSDoc(node) {
                var sourceCode = eslint.getSourceCode();
                var jsdoc = sourceCode.getJSDocComment(node);

                assert.isNull(jsdoc);
            }

            var spy = sandbox.spy(assertJSDoc);

            eslint.on("FunctionDeclaration", spy);
            eslint.verify(code, { rules: {}, parserOptions: { ecmaVersion: 6 }}, filename, true);
            assert.isTrue(spy.calledOnce, "Event handler should be called.");
        });

    });

    describe("getComments()", function() {
        var config = { rules: {} };

        /**
         * Check comment count
         * @param {int} leading Leading comment count
         * @param {int} trailing Trailing comment count
         * @returns {Function} function to execute
         * @private
         */
        function assertCommentCount(leading, trailing) {
            return function(node) {
                var sourceCode = eslint.getSourceCode();
                var comments = sourceCode.getComments(node);

                assert.equal(comments.leading.length, leading);
                assert.equal(comments.trailing.length, trailing);
            };
        }

        it("should attach them to all nodes", function() {
            var code = [
                "// my line comment",
                "var a = 42;",
                "/* my block comment */"
            ].join("\n");

            eslint.reset();
            eslint.on("Program", assertCommentCount(0, 0));
            eslint.on("VariableDeclaration", assertCommentCount(1, 1));
            eslint.on("VariableDeclarator", assertCommentCount(0, 0));
            eslint.on("Identifier", assertCommentCount(0, 0));
            eslint.on("Literal", assertCommentCount(0, 0));

            eslint.verify(code, config, "", true);
        });

        it("should not attach leading comments from previous node", function() {
            var code = [
                "function a() {",
                "    var b = {",
                "        // comment",
                "    };",
                "    return b;",
                "}"
            ].join("\n");

            eslint.reset();
            eslint.on("Program", assertCommentCount(0, 0));
            eslint.on("Identifier", assertCommentCount(0, 0));
            eslint.on("BlockStatement", assertCommentCount(0, 0));
            eslint.on("VariableDeclaration", assertCommentCount(0, 0));
            eslint.on("VariableDeclarator", assertCommentCount(0, 0));
            eslint.on("ObjectExpression", assertCommentCount(0, 1));
            eslint.on("ReturnStatement", assertCommentCount(0, 0));

            eslint.verify(code, config, "", true);
        });

        it("should not attach duplicate leading comments from previous node", function() {
            var code = [
                "//foo",
                "var zzz /*aaa*/ = 777;",
                "//bar"
            ].join("\n");

            eslint.reset();
            eslint.on("Program", assertCommentCount(0, 0));
            eslint.on("VariableDeclaration", assertCommentCount(1, 1));
            eslint.on("VariableDeclarator", assertCommentCount(0, 0));
            eslint.on("Identifier", assertCommentCount(0, 1));
            eslint.on("Literal", assertCommentCount(1, 0));

            eslint.verify(code, config, "", true);
        });
    });

    describe("getLines()", function() {

        it("should get proper lines when using \\n as a line break", function() {
            var code = "a;\nb;",
                ast = espree.parse(code, DEFAULT_CONFIG),
                sourceCode = new SourceCode(code, ast);

            var lines = sourceCode.getLines();

            assert.equal(lines[0], "a;");
            assert.equal(lines[1], "b;");
        });

        it("should get proper lines when using \\r\\n as a line break", function() {
            var code = "a;\r\nb;",
                ast = espree.parse(code, DEFAULT_CONFIG),
                sourceCode = new SourceCode(code, ast);

            var lines = sourceCode.getLines();

            assert.equal(lines[0], "a;");
            assert.equal(lines[1], "b;");
        });

        it("should get proper lines when using \\r as a line break", function() {
            var code = "a;\rb;",
                ast = espree.parse(code, DEFAULT_CONFIG),
                sourceCode = new SourceCode(code, ast);

            var lines = sourceCode.getLines();

            assert.equal(lines[0], "a;");
            assert.equal(lines[1], "b;");
        });

        it("should get proper lines when using \\u2028 as a line break", function() {
            var code = "a;\u2028b;",
                ast = espree.parse(code, DEFAULT_CONFIG),
                sourceCode = new SourceCode(code, ast);

            var lines = sourceCode.getLines();

            assert.equal(lines[0], "a;");
            assert.equal(lines[1], "b;");
        });

        it("should get proper lines when using \\u2029 as a line break", function() {
            var code = "a;\u2029b;",
                ast = espree.parse(code, DEFAULT_CONFIG),
                sourceCode = new SourceCode(code, ast);

            var lines = sourceCode.getLines();

            assert.equal(lines[0], "a;");
            assert.equal(lines[1], "b;");
        });

    });

    describe("getText()", function() {

        var sourceCode,
            ast;

        beforeEach(function() {
            ast = espree.parse(TEST_CODE, DEFAULT_CONFIG);
            sourceCode = new SourceCode(TEST_CODE, ast);
        });

        it("should retrieve all text when used without parameters", function() {
            var text = sourceCode.getText();

            assert.equal(text, TEST_CODE);
        });

        it("should retrieve all text for root node", function() {
            var text = sourceCode.getText(ast);

            assert.equal(text, TEST_CODE);
        });

        it("should clamp to valid range when retrieving characters before start of source", function() {
            var text = sourceCode.getText(ast, 2, 0);

            assert.equal(text, TEST_CODE);
        });

        it("should retrieve all text for binary expression", function() {

            var node = ast.body[0].declarations[0].init;
            var text = sourceCode.getText(node);

            assert.equal(text, "6 * 7");
        });

        it("should retrieve all text plus two characters before for binary expression", function() {

            var node = ast.body[0].declarations[0].init;
            var text = sourceCode.getText(node, 2);

            assert.equal(text, "= 6 * 7");
        });

        it("should retrieve all text plus one character after for binary expression", function() {
            var node = ast.body[0].declarations[0].init;
            var text = sourceCode.getText(node, 0, 1);

            assert.equal(text, "6 * 7;");
        });

        it("should retrieve all text plus two characters before and one character after for binary expression", function() {
            var node = ast.body[0].declarations[0].init;
            var text = sourceCode.getText(node, 2, 1);

            assert.equal(text, "= 6 * 7;");
        });

    });

    describe("getNodeByRangeIndex()", function() {

        var sourceCode,
            ast;

        beforeEach(function() {
            ast = espree.parse(TEST_CODE, DEFAULT_CONFIG);
            sourceCode = new SourceCode(TEST_CODE, ast);
        });

        it("should retrieve a node starting at the given index", function() {
            var node = sourceCode.getNodeByRangeIndex(4);

            assert.equal(node.type, "Identifier");
        });

        it("should retrieve a node containing the given index", function() {
            var node = sourceCode.getNodeByRangeIndex(6);

            assert.equal(node.type, "Identifier");
        });

        it("should retrieve a node that is exactly the given index", function() {
            var node = sourceCode.getNodeByRangeIndex(13);

            assert.equal(node.type, "Literal");
            assert.equal(node.value, 6);
        });

        it("should retrieve a node ending with the given index", function() {
            var node = sourceCode.getNodeByRangeIndex(9);

            assert.equal(node.type, "Identifier");
        });

        it("should retrieve the deepest node containing the given index", function() {
            var node = sourceCode.getNodeByRangeIndex(14);

            assert.equal(node.type, "BinaryExpression");
            node = sourceCode.getNodeByRangeIndex(3);
            assert.equal(node.type, "VariableDeclaration");
        });

        it("should return null if the index is outside the range of any node", function() {
            var node = sourceCode.getNodeByRangeIndex(-1);

            assert.isNull(node);
            node = sourceCode.getNodeByRangeIndex(-99);
            assert.isNull(node);
        });

        it("should attach the node's parent", function() {
            var node = sourceCode.getNodeByRangeIndex(14);

            assert.property(node, "parent");
            assert.equal(node.parent.type, "VariableDeclarator");
        });

        it("should not modify the node when attaching the parent", function() {
            var node = sourceCode.getNodeByRangeIndex(10);

            assert.equal(node.type, "VariableDeclarator");
            node = sourceCode.getNodeByRangeIndex(4);
            assert.equal(node.type, "Identifier");
            assert.property(node, "parent");
            assert.equal(node.parent.type, "VariableDeclarator");
            assert.notProperty(node.parent, "parent");
        });

    });

    describe("isSpaceBetweenTokens()", function() {

        leche.withData([
            ["let foo = bar;", true],
            ["let  foo = bar;", true],
            ["let /**/ foo = bar;", true],
            ["let/**/foo = bar;", false],
            ["a+b", false],
            ["a/**/+b", false],
            ["a/* */+b", false],
            ["a/**/ +b", true],
            ["a/**/ /**/+b", true],
            ["a/**/\n/**/+b", true],
            ["a +b", true]
        ], function(code, expected) {

            it("should return true when there is one space between tokens", function() {
                var ast = espree.parse(code, DEFAULT_CONFIG),
                    sourceCode = new SourceCode(code, ast);

                assert.equal(
                    sourceCode.isSpaceBetweenTokens(
                        sourceCode.ast.tokens[0], sourceCode.ast.tokens[1]
                    ),
                    expected
                );
            });
        });
    });

    // need to check that eslint.verify() works with SourceCode

    describe("eslint.verify()", function() {

        var CONFIG = {
            parserOptions: { ecmaVersion: 6 }
        };

        it("should work when passed a SourceCode object without a config", function() {
            var ast = espree.parse(TEST_CODE, DEFAULT_CONFIG);

            var sourceCode = new SourceCode(TEST_CODE, ast),
                messages = eslint.verify(sourceCode);

            assert.equal(messages.length, 0);
        });

        it("should work when passed a SourceCode object containing ES6 syntax and config", function() {
            var sourceCode = new SourceCode("let foo = bar;", AST),
                messages = eslint.verify(sourceCode, CONFIG);

            assert.equal(messages.length, 0);
        });

        it("should report an error when using let and blockBindings is false", function() {
            var sourceCode = new SourceCode("let foo = bar;", AST),
                messages = eslint.verify(sourceCode, {
                    parserOptions: { ecmaVersion: 6 },
                    rules: { "no-unused-vars": 2 }
                });

            assert.equal(messages.length, 1);
            assert.equal(messages[0].message, "'foo' is defined but never used");
        });
    });
});

redpajama_set_name: RedPajamaGithub


text:
file(REMOVE_RECURSE
  "libethash-global-context.a"
)


text:
#include <boost/test/test_tools.hpp>
#include <boost/test/unit_test.hpp>

#include <boost/assign.hpp>
#include <boost/bind.hpp>
#include <algorithm>
#include <functional>
#include <list>
#include <numeric>
#include <deque>
#include <vector>

namespace boost
{
    namespace
    {
        template<class Container>
        void test_stable_sort_impl(Container& cont)
        {
            Container reference(cont);
            Container test(cont);

            boost::stable_sort(test);
            std::stable_sort(reference.begin(), reference.end());

            BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(),
                                           test.begin(), test.end() );

            test = cont;
            boost::stable_sort(boost::make_iterator_range(test));
            BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(),
                                           test.begin(), test.end() );
        }

        template<class Container, class BinaryPredicate>
        void test_stable_sort_impl(Container& cont, BinaryPredicate pred)
        {
            Container reference(cont);
            Container test(cont);

            boost::stable_sort(test, pred);
            std::stable_sort(reference.begin(), reference.end(), pred);

            BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(),
                                           test.begin(), test.end() );

            test = cont;
            boost::stable_sort(boost::make_iterator_range(test), pred);
            BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(),
                                           test.begin(), test.end() );
        }

        template<class Container>
        void test_stable_sort_impl()
        {
            using namespace boost::assign;

            Container cont;
            test_stable_sort_impl(cont);
            test_stable_sort_impl(cont, std::less<int>());
            test_stable_sort_impl(cont, std::greater<int>());

            cont.clear();
            cont += 1;
            test_stable_sort_impl(cont);
            test_stable_sort_impl(cont, std::less<int>());
            test_stable_sort_impl(cont, std::greater<int>());

            cont.clear();
            cont += 1,2,3,4,5,6,7,8,9;
            test_stable_sort_impl(cont);
            test_stable_sort_impl(cont, std::less<int>());
            test_stable_sort_impl(cont, std::greater<int>());
        }

        void test_stable_sort()
        {
            test_stable_sort_impl< std::vector<int> >();
            test_stable_sort_impl< std::deque<int> >();
        }
    }
}

boost::unit_test::test_suite*
init_unit_test_suite(int argc, char* argv[])
{
    boost::unit_test::test_suite* test
        = BOOST_TEST_SUITE( "RangeTestSuite.algorithm.stable_sort" );

    test->add( BOOST_TEST_CASE( &boost::test_stable_sort ) );

    return test;
}


text:
package com.founder.fix.fixflow.editor.language.json.converter;

import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;

import com.founder.fix.fixflow.editor.constants.EditorJsonConstants;
import com.founder.fix.fixflow.editor.constants.StencilConstants;

public class BpmnJsonConverterUtil implements EditorJsonConstants, StencilConstants {

  private static ObjectMapper objectMapper = new ObjectMapper();

  public static ObjectNode createChildShape(String id, String type, double lowerRightX, double lowerRightY, double upperLeftX, double upperLeftY) {
    ObjectNode shapeNode = objectMapper.createObjectNode();
    shapeNode.put(EDITOR_BOUNDS, createBoundsNode(lowerRightX, lowerRightY, upperLeftX, upperLeftY));
    shapeNode.put(EDITOR_SHAPE_ID, id);
    ArrayNode shapesArrayNode = objectMapper.createArrayNode();
    shapeNode.put(EDITOR_CHILD_SHAPES, shapesArrayNode);
    ObjectNode stencilNode = objectMapper.createObjectNode();
    stencilNode.put(EDITOR_STENCIL_ID, type);
    shapeNode.put(EDITOR_STENCIL, stencilNode);
    return shapeNode;
  }

  public static ObjectNode createBoundsNode(double lowerRightX, double lowerRightY, double upperLeftX, double upperLeftY) {
    ObjectNode boundsNode = objectMapper.createObjectNode();
    boundsNode.put(EDITOR_BOUNDS_LOWER_RIGHT, createPositionNode(lowerRightX, lowerRightY));
    boundsNode.put(EDITOR_BOUNDS_UPPER_LEFT, createPositionNode(upperLeftX, upperLeftY));
    return boundsNode;
  }

  public static ObjectNode createPositionNode(double x, double y) {
    ObjectNode positionNode = objectMapper.createObjectNode();
    positionNode.put(EDITOR_BOUNDS_X, x);
    positionNode.put(EDITOR_BOUNDS_Y, y);
    return positionNode;
  }

  public static ObjectNode createResourceNode(String id) {
    ObjectNode resourceNode = objectMapper.createObjectNode();
    resourceNode.put(EDITOR_SHAPE_ID, id);
    return resourceNode;
  }

  public static String getStencilId(JsonNode objectNode) {
    String stencilId = null;
    JsonNode stencilNode = objectNode.get(EDITOR_STENCIL);
    if (stencilNode != null && stencilNode.get(EDITOR_STENCIL_ID) != null) {
      stencilId = stencilNode.get(EDITOR_STENCIL_ID).asText();
    }
    return stencilId;
  }

  public static String getElementId(JsonNode objectNode) {
    String elementId = null;
    if (StringUtils.isNotEmpty(getPropertyValueAsString(PROPERTY_OVERRIDE_ID, objectNode))) {
      elementId = getPropertyValueAsString(PROPERTY_OVERRIDE_ID, objectNode).trim();
    } else {
      elementId = objectNode.get(EDITOR_SHAPE_ID).asText();
    }

    return elementId;
  }

  protected static String getPropertyValueAsString(String name, JsonNode objectNode) {
    String propertyValue = null;
    JsonNode propertyNode = getProperty(name, objectNode);
    if (propertyNode != null) {
      propertyValue = propertyNode.asText();
    }
    return propertyValue;
  }

  protected static JsonNode getProperty(String name, JsonNode objectNode) {
    JsonNode propertyNode = null;
    if (objectNode.get(EDITOR_SHAPE_PROPERTIES) != null) {
      JsonNode propertiesNode = objectNode.get(EDITOR_SHAPE_PROPERTIES);
      propertyNode = propertiesNode.get(name);
    }
    return propertyNode;
  }

  /**
   * 根据elementid 获取对应的shapeId
   * @param elementId
   * @return
   */
  protected static String getFormatShapeId(String elementId){
	  return SHAPE_ID_PREFIX + elementId;
  }

  /**
   * 根据对应的shapeId 获取elementId
   * @param shapeId
   * @return
   */
  protected static String getElementIdFromShapeId(String shapeId){
	  return shapeId.substring(SHAPE_ID_PREFIX.length());
  }

  protected static String getFormatEdgeId(String elementId){
	  return EDGE_ID_PREFIX + elementId;
  }

  protected static String getElementIdFromEdgeId(String edgeId){
	  return edgeId.substring(EDGE_ID_PREFIX.length());
  }
}


text:
package monocle.law.discipline.function

import monocle.function.Snoc1._
import monocle.function._
import monocle.law.discipline.{IsoTests, LensTests}
import org.scalacheck.Arbitrary
import org.typelevel.discipline.Laws

import scalaz.Equal
import scalaz.std.tuple._

object Snoc1Tests extends Laws {

  def apply[S: Equal : Arbitrary, I: Equal : Arbitrary, L: Equal : Arbitrary](implicit evSnoc1: Snoc1[S, I, L],
    arbSLSL: Arbitrary[((I,L)) => ((I,L))], arbSS: Arbitrary[I => I], arbLL: Arbitrary[L => L]): RuleSet =
    new SimpleRuleSet("Snoc1",
      IsoTests(snoc1[S, I, L]).props ++
      LensTests(init[S, I, L]).props ++
      LensTests(last[S, I, L]).props: _*)

}


text:
function Application() {
  L.mapbox.accessToken = 'pk.eyJ1IjoibWljaGFlbGtpcmsiLCJhIjoiNjA3YTM0ODRmOTU3ZmQ2ZTUxMjgyNWI0MDk2ODBiMzAifQ.GOrBk7s9JvPl6h5rDkcJiQ';

  //build the map and center it over DTLA
  var map = L.mapbox.map('map', 'mapbox.dark').setView([34.0510, -118.2500], 15);

  // Where our visualizations get their collision data
  var baseUrl = 'http://api.collision.jackpine.me/api/v1/';

  //give components a way to get their bounds
  var getBoundingBox = function() {
    var bounds = map.getBounds();
    var boundingBox = "" + bounds.getWest() + "," + bounds.getSouth() + "," +  bounds.getEast() + "," + bounds.getNorth();
    return boundingBox;
  }

  // set up visualizatoin components
  this.heatMap = new HeatMap(baseUrl, map, getBoundingBox);
  this.collisionTimeline = new CollisionTimeline(baseUrl, getBoundingBox);

  // initial render
  this.renderWithCurrentBounds();

  // For performance:
  // If the user is clicking around like crazy, rerender only once per second max.
  this.reRenderWithCurrentBounds = _.debounce(this.renderWithCurrentBounds, 1000);

  var application = this;
  //re-render incidents whenever map moves
  map.on('moveend', function() {
    application.reRenderWithCurrentBounds();
  });
}

Application.prototype.renderWithCurrentBounds = function() {
  this.heatMap.renderWithCurrentBounds();
  this.collisionTimeline.renderWithCurrentBounds();
}


text:
module Slacken::Filters
  # Public: Sanitize not allowed tags in list.
  class SanitizeList < Slacken::Filter
    def call(component)
      case component.type.name
      when :ul, :ol, :dl
        component.derive(component.children.map(&method(:sanitize_list)))
      else
        component.derive(component.children.map(&method(:call)))
      end
    end

    def valid?(component)
      case component.type.name
      when :ul, :ol, :dl
        component.children.all?(&method(:list_sanitized?))
      else
        component.children.all?(&method(:valid?))
      end
    end

    private

    def sanitize_list(component)
      if component.type.member_of?(:li, :dd)
        head, *tails = component.children
        component.derive(
          [sanitize_list_item(head), *tails.map(&method(:sanitize_list))]
        )
      elsif component.type.allowed_in_list?
        component.derive(component.children.map(&method(:sanitize_list)))
      else
        component.derive(
          component.children.map(&method(:sanitize_list)),
          type: component.block? ? :div : :span
        )
      end
    end

    def sanitize_list_item(component)
      if component.type.allowed_as_list_item?
        component.derive(component.children.map(&method(:sanitize_list_item)))
      else
        # No block tags are allowed.
        component.derive(component.children.map(&method(:sanitize_list_item)), type: :span)
      end
    end

    def list_sanitized?(component)
      if component.type.allowed_in_list?
        component.children.all?(&method(:list_sanitized?))
      else
        false
      end
    end
  end
end