summaryrefslogtreecommitdiff
path: root/Userland/Applications/Spreadsheet/Readers/Test/TestXSV.cpp
blob: 5dbe2a596618cb7be3b8ad5b4d8762af92911288 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
 * Copyright (c) 2020, the SerenityOS developers.
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <LibTest/TestCase.h>

#include "../CSV.h"
#include "../XSV.h"
#include <AK/ByteBuffer.h>
#include <LibCore/File.h>

TEST_CASE(should_parse_valid_data)
{
    {
        auto data = R"~~~(Foo, Bar, Baz
                      1, 2, 3
                      4, 5, 6
                      """x", y"z, 9)~~~";
        auto csv = Reader::CSV { data, Reader::default_behaviors() | Reader::ParserBehavior::ReadHeaders | Reader::ParserBehavior::TrimLeadingFieldSpaces };
        csv.parse();
        EXPECT(!csv.has_error());

        EXPECT_EQ(csv[0]["Foo"], "1");
        EXPECT_EQ(csv[2]["Foo"], "\"x");
        EXPECT_EQ(csv[2]["Bar"], "y\"z");
    }

    {
        auto data = R"~~~(Foo, Bar, Baz
                      1     	 , 2, 3
                      4, "5 "       , 6
                      """x", y"z, 9                       )~~~";
        auto csv = Reader::CSV { data, Reader::default_behaviors() | Reader::ParserBehavior::ReadHeaders | Reader::ParserBehavior::TrimLeadingFieldSpaces | Reader::ParserBehavior::TrimTrailingFieldSpaces };
        csv.parse();
        EXPECT(!csv.has_error());

        EXPECT_EQ(csv[0]["Foo"], "1");
        EXPECT_EQ(csv[1]["Bar"], "5 ");
        EXPECT_EQ(csv[2]["Foo"], "\"x");
        EXPECT_EQ(csv[2]["Baz"], "9");
    }
}

TEST_CASE(should_fail_nicely)
{
    {
        auto data = R"~~~(Foo, Bar, Baz
                      x, y)~~~";
        auto csv = Reader::CSV { data, Reader::default_behaviors() | Reader::ParserBehavior::ReadHeaders | Reader::ParserBehavior::TrimLeadingFieldSpaces };
        csv.parse();
        EXPECT(csv.has_error());
        EXPECT_EQ(csv.error(), Reader::ReadError::NonConformingColumnCount);
    }

    {
        auto data = R"~~~(Foo, Bar, Baz
                      x, y, "z)~~~";
        auto csv = Reader::CSV { data, Reader::default_behaviors() | Reader::ParserBehavior::ReadHeaders | Reader::ParserBehavior::TrimLeadingFieldSpaces };
        csv.parse();
        EXPECT(csv.has_error());
        EXPECT_EQ(csv.error(), Reader::ReadError::QuoteFailure);
    }
}

TEST_CASE(should_iterate_rows)
{
    auto data = R"~~~(Foo, Bar, Baz
                      1, 2, 3
                      4, 5, 6
                      """x", y"z, 9)~~~";
    auto csv = Reader::CSV { data, Reader::default_behaviors() | Reader::ParserBehavior::ReadHeaders | Reader::ParserBehavior::TrimLeadingFieldSpaces };
    csv.parse();
    EXPECT(!csv.has_error());

    bool ran = false;
    for (auto row : csv)
        ran = !row[0].is_empty();

    EXPECT(ran);
}

BENCHMARK_CASE(fairly_big_data)
{
    constexpr auto num_rows = 100000u;
    constexpr auto line = "well,hello,friends,1,2,3,4,5,6,7,8,pizza,guacamole\n"sv;
    auto buf = ByteBuffer::create_uninitialized((line.length() * num_rows) + 1).release_value();
    buf[buf.size() - 1] = '\0';

    for (size_t row = 0; row <= num_rows; ++row) {
        memcpy(buf.offset_pointer(row * line.length()), line.characters_without_null_termination(), line.length());
    }

    auto csv = Reader::CSV { (char const*)buf.data(), Reader::default_behaviors() | Reader::ParserBehavior::ReadHeaders };
    csv.parse();

    EXPECT(!csv.has_error());
    EXPECT_EQ(csv.size(), num_rows);
}