Skip to content

Commit 2a7b0fc

Browse files
committed
Add JSON generation code to fuzz test numeric types, print integers more
nicely. Add integration tests to Travis CI build matrix. Add ApproxEquals method for floating point comparisons. Add boolean, string, struct, list to generated json test case
1 parent 8995c92 commit 2a7b0fc

19 files changed

Lines changed: 829 additions & 50 deletions

.travis.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ matrix:
4646
jdk: oraclejdk7
4747
script:
4848
- $TRAVIS_BUILD_DIR/ci/travis_script_java.sh
49+
- language: java
50+
os: linux
51+
env: ARROW_TEST_GROUP=integration
52+
jdk: oraclejdk7
53+
before_script:
54+
- export CC="gcc-4.9"
55+
- export CXX="g++-4.9"
56+
- $TRAVIS_BUILD_DIR/ci/travis_before_script_cpp.sh
57+
script:
58+
- $TRAVIS_BUILD_DIR/ci/travis_script_integration.sh
4959

5060
before_install:
5161
- ulimit -c unlimited -S

ci/travis_script_integration.sh

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env bash
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License. See accompanying LICENSE file.
14+
15+
set -e
16+
17+
: ${CPP_BUILD_DIR=$TRAVIS_BUILD_DIR/cpp-build}
18+
19+
JAVA_DIR=${TRAVIS_BUILD_DIR}/java
20+
21+
pushd $JAVA_DIR
22+
23+
mvn package
24+
25+
popd
26+
27+
pushd $TRAVIS_BUILD_DIR/integration
28+
29+
VERSION=0.1.1-SNAPSHOT
30+
export ARROW_JAVA_INTEGRATION_JAR=$JAVA_DIR/tools/target/arrow-tools-$VERSION-jar-with-dependencies.jar
31+
export ARROW_CPP_TESTER=$CPP_BUILD_DIR/debug/json-integration-test
32+
33+
source $TRAVIS_BUILD_DIR/ci/travis_install_conda.sh
34+
export MINICONDA=$HOME/miniconda
35+
export PATH="$MINICONDA/bin:$PATH"
36+
37+
CONDA_ENV_NAME=arrow-integration-test
38+
conda create -y -q -n $CONDA_ENV_NAME python=3.5
39+
source activate $CONDA_ENV_NAME
40+
41+
# faster builds, please
42+
conda install -y nomkl
43+
44+
# Expensive dependencies install from Continuum package repo
45+
conda install -y pip numpy six
46+
47+
python integration_test.py --debug
48+
49+
popd

cpp/src/arrow/array.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ bool Array::EqualsExact(const Array& other) const {
6060
return true;
6161
}
6262

63+
bool Array::ApproxEquals(const std::shared_ptr<Array>& arr) const {
64+
return Equals(arr);
65+
}
66+
6367
Status Array::Validate() const {
6468
return Status::OK();
6569
}

cpp/src/arrow/array.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class ARROW_EXPORT Array {
6262

6363
bool EqualsExact(const Array& arr) const;
6464
virtual bool Equals(const std::shared_ptr<Array>& arr) const = 0;
65+
virtual bool ApproxEquals(const std::shared_ptr<Array>& arr) const;
6566

6667
// Compare if the range of slots specified are equal for the given array and
6768
// this array. end_idx exclusive. This methods does not bounds check.

cpp/src/arrow/ipc/ipc-metadata-test.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,15 @@ const std::shared_ptr<DataType> INT32 = std::make_shared<Int32Type>();
7070

7171
TEST_F(TestSchemaMetadata, PrimitiveFields) {
7272
auto f0 = std::make_shared<Field>("f0", std::make_shared<Int8Type>());
73-
auto f1 = std::make_shared<Field>("f1", std::make_shared<Int16Type>());
73+
auto f1 = std::make_shared<Field>("f1", std::make_shared<Int16Type>(), false);
7474
auto f2 = std::make_shared<Field>("f2", std::make_shared<Int32Type>());
7575
auto f3 = std::make_shared<Field>("f3", std::make_shared<Int64Type>());
7676
auto f4 = std::make_shared<Field>("f4", std::make_shared<UInt8Type>());
7777
auto f5 = std::make_shared<Field>("f5", std::make_shared<UInt16Type>());
7878
auto f6 = std::make_shared<Field>("f6", std::make_shared<UInt32Type>());
7979
auto f7 = std::make_shared<Field>("f7", std::make_shared<UInt64Type>());
8080
auto f8 = std::make_shared<Field>("f8", std::make_shared<FloatType>());
81-
auto f9 = std::make_shared<Field>("f9", std::make_shared<DoubleType>());
81+
auto f9 = std::make_shared<Field>("f9", std::make_shared<DoubleType>(), false);
8282
auto f10 = std::make_shared<Field>("f10", std::make_shared<BooleanType>());
8383

8484
Schema schema({f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10});

cpp/src/arrow/ipc/json-integration-test.cc

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,15 +169,15 @@ static Status ValidateArrowVsJson(
169169
RETURN_NOT_OK(json_reader->GetRecordBatch(i, &json_batch));
170170
RETURN_NOT_OK(arrow_reader->GetRecordBatch(i, &arrow_batch));
171171

172-
if (!json_batch->Equals(*arrow_batch.get())) {
172+
if (!json_batch->ApproxEquals(*arrow_batch.get())) {
173173
std::stringstream ss;
174174
ss << "Record batch " << i << " did not match";
175175

176-
ss << "\nJSON: \n ";
177-
RETURN_NOT_OK(PrettyPrint(*json_batch.get(), &ss));
176+
ss << "\nJSON:\n";
177+
RETURN_NOT_OK(PrettyPrint(*json_batch.get(), 0, &ss));
178178

179-
ss << "\nArrow: \n ";
180-
RETURN_NOT_OK(PrettyPrint(*arrow_batch.get(), &ss));
179+
ss << "\nArrow:\n";
180+
RETURN_NOT_OK(PrettyPrint(*arrow_batch.get(), 0, &ss));
181181
return Status::Invalid(ss.str());
182182
}
183183
}
@@ -299,6 +299,23 @@ static const char* JSON_EXAMPLE = R"example(
299299
"VALIDITY": [1, 0, 0, 1, 1]
300300
}
301301
]
302+
},
303+
{
304+
"count": 4,
305+
"columns": [
306+
{
307+
"name": "foo",
308+
"count": 4,
309+
"DATA": [1, 2, 3, 4],
310+
"VALIDITY": [1, 0, 1, 1]
311+
},
312+
{
313+
"name": "bar",
314+
"count": 4,
315+
"DATA": [1.0, 2.0, 3.0, 4.0],
316+
"VALIDITY": [1, 0, 0, 1]
317+
}
318+
]
302319
}
303320
]
304321
}

cpp/src/arrow/ipc/json-internal.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ class JsonArrayWriter : public ArrayVisitor {
418418

419419
template <typename T>
420420
void WriteOffsetsField(const T* offsets, int32_t length) {
421-
writer_->Key("OFFSETS");
421+
writer_->Key("OFFSET");
422422
writer_->StartArray();
423423
for (int i = 0; i < length; ++i) {
424424
writer_->Int64(offsets[i]);
@@ -810,7 +810,7 @@ class JsonArrayReader {
810810
builder.Append(val.GetUint64());
811811
} else if (IsFloatingPoint<T>::value) {
812812
DCHECK(val.IsFloat());
813-
builder.Append(val.GetFloat());
813+
builder.Append(val.GetDouble());
814814
} else if (std::is_base_of<BooleanType, T>::value) {
815815
DCHECK(val.IsBool());
816816
builder.Append(val.GetBool());
@@ -853,8 +853,8 @@ class JsonArrayReader {
853853
typename std::enable_if<std::is_base_of<ListType, T>::value, Status>::type ReadArray(
854854
const RjObject& json_array, int32_t length, const std::vector<bool>& is_valid,
855855
const std::shared_ptr<DataType>& type, std::shared_ptr<Array>* array) {
856-
const auto& json_offsets = json_array.FindMember("OFFSETS");
857-
RETURN_NOT_ARRAY("OFFSETS", json_offsets, json_array);
856+
const auto& json_offsets = json_array.FindMember("OFFSET");
857+
RETURN_NOT_ARRAY("OFFSET", json_offsets, json_array);
858858
const auto& json_offsets_arr = json_offsets->value.GetArray();
859859

860860
int32_t null_count = 0;

cpp/src/arrow/ipc/metadata-internal.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ Status FieldFromFlatbuffer(const flatbuf::Field* field, std::shared_ptr<Field>*
264264
RETURN_NOT_OK(
265265
TypeFromFlatbuffer(field->type_type(), field->type(), child_fields, &type));
266266

267-
*out = std::make_shared<Field>(field->name()->str(), type);
267+
*out = std::make_shared<Field>(field->name()->str(), type, field->nullable());
268268
return Status::OK();
269269
}
270270

cpp/src/arrow/pretty_print-test.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ class TestArrayPrinter : public ::testing::Test {
4848
};
4949

5050
template <typename TYPE, typename C_TYPE>
51-
void CheckPrimitive(const std::vector<bool>& is_valid, const std::vector<C_TYPE>& values,
52-
const char* expected) {
51+
void CheckPrimitive(int indent, const std::vector<bool>& is_valid,
52+
const std::vector<C_TYPE>& values, const char* expected) {
5353
std::ostringstream sink;
5454

5555
MemoryPool* pool = default_memory_pool();
@@ -66,7 +66,7 @@ void CheckPrimitive(const std::vector<bool>& is_valid, const std::vector<C_TYPE>
6666
std::shared_ptr<Array> array;
6767
ASSERT_OK(builder.Finish(&array));
6868

69-
ASSERT_OK(PrettyPrint(*array.get(), &sink));
69+
ASSERT_OK(PrettyPrint(*array.get(), indent, &sink));
7070

7171
std::string result = sink.str();
7272
ASSERT_EQ(std::string(expected, strlen(expected)), result);
@@ -77,11 +77,11 @@ TEST_F(TestArrayPrinter, PrimitiveType) {
7777

7878
std::vector<int32_t> values = {0, 1, 2, 3, 4};
7979
static const char* expected = R"expected([0, 1, null, 3, null])expected";
80-
CheckPrimitive<Int32Type, int32_t>(is_valid, values, expected);
80+
CheckPrimitive<Int32Type, int32_t>(0, is_valid, values, expected);
8181

8282
std::vector<std::string> values2 = {"foo", "bar", "", "baz", ""};
8383
static const char* ex2 = R"expected(["foo", "bar", null, "baz", null])expected";
84-
CheckPrimitive<StringType, std::string>(is_valid, values2, ex2);
84+
CheckPrimitive<StringType, std::string>(0, is_valid, values2, ex2);
8585
}
8686

8787
} // namespace arrow

cpp/src/arrow/pretty_print.cc

Lines changed: 71 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
// under the License.
1717

1818
#include <ostream>
19+
#include <sstream>
1920
#include <string>
21+
#include <vector>
2022

2123
#include "arrow/array.h"
2224
#include "arrow/pretty_print.h"
@@ -32,20 +34,35 @@ namespace arrow {
3234

3335
class ArrayPrinter : public ArrayVisitor {
3436
public:
35-
ArrayPrinter(const Array& array, std::ostream* sink) : array_(array), sink_(sink) {}
37+
ArrayPrinter(const Array& array, int indent, std::ostream* sink)
38+
: array_(array), indent_(indent), sink_(sink) {}
3639

3740
Status Print() { return VisitArray(array_); }
3841

3942
Status VisitArray(const Array& array) { return array.Accept(this); }
4043

4144
template <typename T>
42-
typename std::enable_if<IsNumeric<T>::value, void>::type WriteDataValues(
45+
typename std::enable_if<IsInteger<T>::value, void>::type WriteDataValues(
4346
const T& array) {
4447
const auto data = array.raw_data();
4548
for (int i = 0; i < array.length(); ++i) {
4649
if (i > 0) { (*sink_) << ", "; }
4750
if (array.IsNull(i)) {
4851
(*sink_) << "null";
52+
} else {
53+
(*sink_) << static_cast<int64_t>(data[i]);
54+
}
55+
}
56+
}
57+
58+
template <typename T>
59+
typename std::enable_if<IsFloatingPoint<T>::value, void>::type WriteDataValues(
60+
const T& array) {
61+
const auto data = array.raw_data();
62+
for (int i = 0; i < array.length(); ++i) {
63+
if (i > 0) { (*sink_) << ", "; }
64+
if (array.IsNull(i)) {
65+
Write("null");
4966
} else {
5067
(*sink_) << data[i];
5168
}
@@ -60,7 +77,7 @@ class ArrayPrinter : public ArrayVisitor {
6077
for (int i = 0; i < array.length(); ++i) {
6178
if (i > 0) { (*sink_) << ", "; }
6279
if (array.IsNull(i)) {
63-
(*sink_) << "null";
80+
Write("null");
6481
} else {
6582
const char* buf = reinterpret_cast<const char*>(array.GetValue(i, &length));
6683
(*sink_) << "\"" << std::string(buf, length) << "\"";
@@ -74,9 +91,9 @@ class ArrayPrinter : public ArrayVisitor {
7491
for (int i = 0; i < array.length(); ++i) {
7592
if (i > 0) { (*sink_) << ", "; }
7693
if (array.IsNull(i)) {
77-
(*sink_) << "null";
94+
Write("null");
7895
} else {
79-
(*sink_) << (array.Value(i) ? "true" : "false");
96+
Write(array.Value(i) ? "true" : "false");
8097
}
8198
}
8299
}
@@ -148,42 +165,77 @@ class ArrayPrinter : public ArrayVisitor {
148165
}
149166

150167
Status Visit(const ListArray& array) override {
151-
// auto type = static_cast<const ListType*>(array.type().get());
152-
// for (size_t i = 0; i < fields.size(); ++i) {
153-
// RETURN_NOT_OK(VisitArray(fields[i]->name, *arrays[i].get()));
154-
// }
155-
// return WriteChildren(type->children(), {array.values()});
168+
Newline();
169+
Write("-- is_valid: ");
170+
BooleanArray is_valid(array.length(), array.null_bitmap());
171+
PrettyPrint(is_valid, indent_ + 2, sink_);
172+
173+
Newline();
174+
Write("-- offsets: ");
175+
Int32Array offsets(array.length() + 1, array.offsets());
176+
PrettyPrint(offsets, indent_ + 2, sink_);
177+
178+
Newline();
179+
Write("-- values: ");
180+
PrettyPrint(*array.values().get(), indent_ + 2, sink_);
181+
156182
return Status::OK();
157183
}
158184

159185
Status Visit(const StructArray& array) override {
160-
// auto type = static_cast<const StructType*>(array.type().get());
161-
// for (size_t i = 0; i < fields.size(); ++i) {
162-
// RETURN_NOT_OK(VisitArray(fields[i]->name, *arrays[i].get()));
163-
// }
164-
// return WriteChildren(type->children(), array.fields());
186+
Newline();
187+
Write("-- is_valid: ");
188+
BooleanArray is_valid(array.length(), array.null_bitmap());
189+
PrettyPrint(is_valid, indent_ + 2, sink_);
190+
191+
const std::vector<std::shared_ptr<Array>>& fields = array.fields();
192+
for (size_t i = 0; i < fields.size(); ++i) {
193+
Newline();
194+
std::stringstream ss;
195+
ss << "-- child " << i << " type: " << fields[i]->type()->ToString() << " values: ";
196+
Write(ss.str());
197+
PrettyPrint(*fields[i].get(), indent_ + 2, sink_);
198+
}
199+
165200
return Status::OK();
166201
}
167202

168203
Status Visit(const UnionArray& array) override {
169204
return Status::NotImplemented("union");
170205
}
171206

207+
void Write(const char* data) { (*sink_) << data; }
208+
209+
void Write(const std::string& data) { (*sink_) << data; }
210+
211+
void Newline() {
212+
(*sink_) << "\n";
213+
Indent();
214+
}
215+
216+
void Indent() {
217+
for (int i = 0; i < indent_; ++i) {
218+
(*sink_) << " ";
219+
}
220+
}
221+
172222
private:
173223
const Array& array_;
224+
int indent_;
225+
174226
std::ostream* sink_;
175227
};
176228

177-
Status PrettyPrint(const Array& arr, std::ostream* sink) {
178-
ArrayPrinter printer(arr, sink);
229+
Status PrettyPrint(const Array& arr, int indent, std::ostream* sink) {
230+
ArrayPrinter printer(arr, indent, sink);
179231
return printer.Print();
180232
}
181233

182-
Status PrettyPrint(const RecordBatch& batch, std::ostream* sink) {
234+
Status PrettyPrint(const RecordBatch& batch, int indent, std::ostream* sink) {
183235
for (int i = 0; i < batch.num_columns(); ++i) {
184236
const std::string& name = batch.column_name(i);
185237
(*sink) << name << ": ";
186-
RETURN_NOT_OK(PrettyPrint(*batch.column(i).get(), sink));
238+
RETURN_NOT_OK(PrettyPrint(*batch.column(i).get(), indent + 2, sink));
187239
(*sink) << "\n";
188240
}
189241
return Status::OK();

0 commit comments

Comments
 (0)