aboutsummaryrefslogtreecommitdiffstats
path: root/document/src/tests/fieldvalue/referencefieldvalue_test.cpp
blob: 8dc5778055a117deed005a1aa090c313cdf9688a (plain) (blame)
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/document/base/field.h>
#include <vespa/document/datatype/referencedatatype.h>
#include <vespa/document/fieldvalue/referencefieldvalue.h>
#include <vespa/document/fieldvalue/stringfieldvalue.h>
#include <vespa/vespalib/testkit/testapp.h>
#include <vespa/vespalib/util/exceptions.h>
#include <ostream>

using namespace document;

namespace {

struct Fixture {
    DocumentType docType{"foo"};
    ReferenceDataType refType{docType, 12345};

    DocumentType otherDocType{"bar"};
    ReferenceDataType otherRefType{otherDocType, 54321};
    Fixture();
    ~Fixture();
};

    Fixture::Fixture() = default;
    Fixture::~Fixture() = default;
}

using vespalib::IllegalArgumentException;

TEST_F("Default-constructed reference is empty and bound to type", Fixture) {
    ReferenceFieldValue fv(f.refType);
    ASSERT_TRUE(fv.getDataType() != nullptr);
    EXPECT_EQUAL(f.refType, *fv.getDataType());
    ASSERT_FALSE(fv.hasValidDocumentId());
}

TEST_F("Reference can be constructed with document ID", Fixture) {
    ReferenceFieldValue fv(f.refType, DocumentId("id:ns:foo::itsa-me"));
    ASSERT_TRUE(fv.getDataType() != nullptr);
    EXPECT_EQUAL(f.refType, *fv.getDataType());
    ASSERT_TRUE(fv.hasValidDocumentId());
    EXPECT_EQUAL(DocumentId("id:ns:foo::itsa-me"), fv.getDocumentId());
}

TEST_F("Exception is thrown if constructor doc ID type does not match referenced document type", Fixture) {
    EXPECT_EXCEPTION(
            ReferenceFieldValue(f.refType, DocumentId("id:ns:bar::wario-time")),
            IllegalArgumentException,
            "Can't assign document ID 'id:ns:bar::wario-time' (of type 'bar') "
            "to reference of document type 'foo'");
}

TEST_F("assign()ing a non-reference field value throws exception", Fixture) {
    ReferenceFieldValue fv(f.refType);
    EXPECT_EXCEPTION(fv.assign(StringFieldValue("waluigi time!!")),
                     IllegalArgumentException,
                     "Can't assign field value of type String to a "
                     "ReferenceFieldValue");
}

TEST_F("Can explicitly assign new document ID to reference", Fixture) {
    ReferenceFieldValue fv(f.refType);
    fv.setDeserializedDocumentId(DocumentId("id:ns:foo::yoshi-eggs"));

    ASSERT_TRUE(fv.hasValidDocumentId());
    EXPECT_EQUAL(DocumentId("id:ns:foo::yoshi-eggs"), fv.getDocumentId());
    // Type remains unchanged
    EXPECT_EQUAL(f.refType, *fv.getDataType());
}

TEST_F("Exception is thrown if explicitly assigned doc ID does not have same type as reference target type", Fixture) {
    ReferenceFieldValue fv(f.refType);

    EXPECT_EXCEPTION(
            fv.setDeserializedDocumentId(DocumentId("id:ns:bar::another-castle")),
            IllegalArgumentException,
            "Can't assign document ID 'id:ns:bar::another-castle' (of type "
            "'bar') to reference of document type 'foo'");
}

TEST_F("assign()ing another reference field value assigns doc ID and type", Fixture) {
    ReferenceFieldValue src(f.refType, DocumentId("id:ns:foo::yoshi"));
    ReferenceFieldValue dest(f.otherRefType);

    dest.assign(src);
    ASSERT_TRUE(dest.hasValidDocumentId());
    EXPECT_EQUAL(src.getDocumentId(), dest.getDocumentId());
    EXPECT_EQUAL(src.getDataType(), dest.getDataType());
}


TEST_F("clone()ing creates new instance with same ID and type", Fixture) {
    ReferenceFieldValue src(f.refType, DocumentId("id:ns:foo::yoshi"));

    std::unique_ptr<ReferenceFieldValue> cloned(src.clone());
    ASSERT_TRUE(cloned);
    ASSERT_TRUE(cloned->hasValidDocumentId());
    EXPECT_EQUAL(src.getDocumentId(), cloned->getDocumentId());
    EXPECT_EQUAL(src.getDataType(), cloned->getDataType());
}

TEST_F("Can clone() value without document ID", Fixture) {
    ReferenceFieldValue src(f.refType);

    std::unique_ptr<ReferenceFieldValue> cloned(src.clone());
    ASSERT_TRUE(cloned);
    EXPECT_FALSE(cloned->hasValidDocumentId());
    EXPECT_EQUAL(src.getDataType(), cloned->getDataType());
}

TEST_F("compare() orders first on type ID, then on document ID", Fixture) {
    // foo type has id 12345
    ReferenceFieldValue fvType1Id1(f.refType, DocumentId("id:ns:foo::AA"));
    ReferenceFieldValue fvType1Id2(f.refType, DocumentId("id:ns:foo::AB"));
    // bar type has id 54321
    ReferenceFieldValue fvType2Id1(f.otherRefType, DocumentId("id:ns:bar::AA"));
    ReferenceFieldValue fvType2Id2(f.otherRefType, DocumentId("id:ns:bar::AB"));

    // Different types
    EXPECT_TRUE(fvType1Id1.compare(fvType2Id1) < 0);
    EXPECT_TRUE(fvType2Id1.compare(fvType1Id1) > 0);

    // Same types, different IDs
    EXPECT_TRUE(fvType1Id1.compare(fvType1Id2) < 0);
    EXPECT_TRUE(fvType1Id2.compare(fvType1Id1) > 0);
    EXPECT_TRUE(fvType2Id1.compare(fvType2Id2) < 0);

    // Different types and IDs
    EXPECT_TRUE(fvType1Id1.compare(fvType2Id2) < 0);
    EXPECT_TRUE(fvType2Id2.compare(fvType1Id1) > 0);

    // Equal types and ID 
    EXPECT_EQUAL(0, fvType1Id1.compare(fvType1Id1));
    EXPECT_EQUAL(0, fvType1Id2.compare(fvType1Id2));
    EXPECT_EQUAL(0, fvType2Id1.compare(fvType2Id1));
}

TEST_F("print() includes reference type and document ID", Fixture) {
    ReferenceFieldValue src(f.refType, DocumentId("id:ns:foo::yoshi"));
    std::ostringstream ss;
    src.print(ss, false, "");
    EXPECT_EQUAL("ReferenceFieldValue(ReferenceDataType(foo, id 12345), "
                 "DocumentId(id:ns:foo::yoshi))", ss.str());
}

TEST_F("print() only indents start of output line", Fixture) {
    ReferenceFieldValue src(f.refType, DocumentId("id:ns:foo::yoshi"));
    std::ostringstream ss;
    src.print(ss, false, "    ");
    EXPECT_EQUAL("    ReferenceFieldValue(ReferenceDataType(foo, id 12345), "
                 "DocumentId(id:ns:foo::yoshi))", ss.str());
}

TEST_MAIN() { TEST_RUN_ALL(); }