Skip to content

Commit 79a61b8

Browse files
refactor tests with insta
1 parent ac72740 commit 79a61b8

File tree

5 files changed

+144
-154
lines changed

5 files changed

+144
-154
lines changed

.gitignore

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,59 @@
1+
# License
12
# Licensed to the Apache Software Foundation (ASF) under one
2-
# or more contributor license agreements. See the NOTICE file
3+
# or more contributor license agreements. See the NOTICE file
34
# distributed with this work for additional information
4-
# regarding copyright ownership. The ASF licenses this file
5+
# regarding copyright ownership. The ASF licenses this file
56
# to you under the Apache License, Version 2.0 (the
67
# "License"); you may not use this file except in compliance
7-
# with the License. You may obtain a copy of the License at
8+
# with the License. You may obtain a copy of the License at
89
#
9-
# http://www.apache.org/licenses/LICENSE-2.0
10+
# http://www.apache.org/licenses/LICENSE-2.0
1011
#
1112
# Unless required by applicable law or agreed to in writing,
1213
# software distributed under the License is distributed on an
1314
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14-
# KIND, either express or implied. See the License for the
15+
# KIND, either express or implied. See the License for the
1516
# specific language governing permissions and limitations
1617
# under the License.
1718

18-
apache-rat-*.jar
19-
2019
# Linux perf sample data
2120
perf.data
2221
perf.data.old
2322

24-
23+
# IDE and editor directories
2524
.vscode
2625
.idea/
2726
.pytest_cache/
28-
pkgs
29-
docker_cache
30-
.gdb_history
31-
*.orig
32-
.*.swp
33-
.*.swo
3427

28+
# Python virtual environments
3529
venv/*
3630

3731
# macOS
3832
.DS_Store
3933

40-
# docker volumes used for caching
34+
# Docker volumes used for caching
4135
.docker
4236

43-
# Rust
37+
# Rust build output
4438
target
4539
Cargo.lock
46-
!datafusion-cli/Cargo.lock
4740

48-
rusty-tags.vi
41+
# Backup files
42+
*.orig
43+
.gdb_history
4944
.history
50-
.flatbuffers/
51-
52-
# apache release artifacts
53-
dev/dist
54-
55-
# CI
56-
arrow-ballista
5745

58-
datafusion/CHANGELOG.md.bak
59-
.githubchangeloggenerator.cache*
46+
# Swap files
47+
.*.swp
48+
.*.swo
6049

61-
# Generated tpch data
62-
datafusion/sqllogictests/test_files/tpch/data/*
50+
# Rust-specific tools
51+
rusty-tags.vi
6352

64-
# Scratch temp dir for sqllogictests
65-
datafusion/sqllogictest/test_files/scratch*
53+
# Apache release artifacts
54+
dev/dist
6655

67-
# rat
56+
# Apache RAT report files
6857
filtered_rat.txt
6958
rat.txt
59+
.githubchangeloggenerator.cache*

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ paste = "1"
4242
[dev-dependencies]
4343
arrow = { version = "53.0.0", features = ["test_utils"] }
4444
criterion = { version = "0.5", features = ["async_tokio"] }
45+
insta = { version = "1.40.0", features = ["yaml"] }
4546
tokio = { version = "1.36", features = ["full"] }
4647

4748
[lints.clippy]

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# datafusion-functions-extra
22

3-
<!-- [![CI](https://github.com/datafusion-contrib/datafusion-functions-json/actions/workflows/ci.yml/badge.svg?event=push)](https://github.com/datafusion-contrib/datafusion-functions-json/actions/workflows/ci.yml?query=branch%3Amain) -->
4-
<!-- [![Crates.io](https://img.shields.io/crates/v/datafusion-functions-json?color=green)](https://crates.io/crates/datafusion-functions-json) -->
3+
[![CI](https://github.com/datafusion-contrib/datafusion-functions-extra/actions/workflows/ci.yml/badge.svg?event=push)](https://github.com/datafusion-contrib/datafusion-functions-extra/actions/workflows/ci.yml?query=branch%3Amain)
4+
<!-- [![Crates.io](https://img.shields.io/crates/v/datafusion-functions-extra?color=green)](https://crates.io/crates/datafusion-functions-extra) -->
55

66
**Note:** This is not an official Apache Software Foundation release.
77

tests/main.rs

Lines changed: 79 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,48 +15,103 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18-
use arrow::datatypes::{DataType, TimeUnit};
19-
use utils::{display_val, run_query};
18+
use crate::utils::TestExecution;
2019

2120
mod utils;
2221

22+
static TEST_TABLE: &str = r#"
23+
CREATE TABLE test_table (
24+
utf8_col VARCHAR,
25+
int64_col BIGINT,
26+
float64_col DOUBLE,
27+
date64_col DATE,
28+
time64_col TIME
29+
) AS VALUES
30+
('apple', 1, 1.0, DATE '2021-01-01', TIME '01:00:00'),
31+
('banana', 2, 2.0, DATE '2021-01-02', TIME '02:00:00'),
32+
('apple', 2, 2.0, DATE '2021-01-02', TIME '02:00:00'),
33+
('orange', 3, 3.0, DATE '2021-01-03', TIME '03:00:00'),
34+
('banana', 3, 3.0, DATE '2021-01-03', TIME '03:00:00'),
35+
('apple', 3, 3.0, DATE '2021-01-03', TIME '03:00:00'),
36+
(NULL, NULL, NULL, NULL, NULL);
37+
"#;
38+
2339
#[tokio::test]
2440
async fn test_mode_utf8() {
25-
let sql = "SELECT MODE(utf8_col) FROM test_table";
26-
let batches = run_query(sql).await.unwrap();
27-
assert_eq!(display_val(batches).await, (DataType::Utf8, "apple".to_string()));
28-
}
41+
let mut execution = TestExecution::new().await.unwrap().with_setup(TEST_TABLE).await;
42+
43+
let actual = execution.run_and_format("SELECT MODE(utf8_col) FROM test_table").await;
2944

45+
insta::assert_yaml_snapshot!(actual, @r###"
46+
- +---------------------------+
47+
- "| mode(test_table.utf8_col) |"
48+
- +---------------------------+
49+
- "| apple |"
50+
- +---------------------------+
51+
"###);
52+
}
3053
#[tokio::test]
3154
async fn test_mode_int64() {
32-
let sql = "SELECT MODE(int64_col) FROM test_table";
33-
let batches = run_query(sql).await.unwrap();
34-
assert_eq!(display_val(batches).await, (DataType::Int64, "3".to_string()));
55+
let mut execution = TestExecution::new().await.unwrap().with_setup(TEST_TABLE).await;
56+
57+
let actual = execution.run_and_format("SELECT MODE(int64_col) FROM test_table").await;
58+
59+
insta::assert_yaml_snapshot!(actual, @r###"
60+
- +----------------------------+
61+
- "| mode(test_table.int64_col) |"
62+
- +----------------------------+
63+
- "| 3 |"
64+
- +----------------------------+
65+
"###);
3566
}
3667

3768
#[tokio::test]
3869
async fn test_mode_float64() {
39-
let sql = "SELECT MODE(float64_col) FROM test_table";
40-
let batches = run_query(sql).await.unwrap();
41-
assert_eq!(display_val(batches).await, (DataType::Float64, "3.0".to_string()));
70+
let mut execution = TestExecution::new().await.unwrap().with_setup(TEST_TABLE).await;
71+
72+
let actual = execution
73+
.run_and_format("SELECT MODE(float64_col) FROM test_table")
74+
.await;
75+
76+
insta::assert_yaml_snapshot!(actual, @r###"
77+
- +------------------------------+
78+
- "| mode(test_table.float64_col) |"
79+
- +------------------------------+
80+
- "| 3.0 |"
81+
- +------------------------------+
82+
"###);
4283
}
4384

4485
#[tokio::test]
4586
async fn test_mode_date64() {
46-
let sql = "SELECT MODE(date64_col) FROM test_table";
47-
let batches = run_query(sql).await.unwrap();
48-
assert_eq!(
49-
display_val(batches).await,
50-
(DataType::Date64, "2021-01-03T00:00:00".to_string())
51-
);
87+
let mut execution = TestExecution::new().await.unwrap().with_setup(TEST_TABLE).await;
88+
89+
let actual = execution
90+
.run_and_format("SELECT MODE(date64_col) FROM test_table")
91+
.await;
92+
93+
insta::assert_yaml_snapshot!(actual, @r###"
94+
- +-----------------------------+
95+
- "| mode(test_table.date64_col) |"
96+
- +-----------------------------+
97+
- "| 2021-01-03 |"
98+
- +-----------------------------+
99+
"###);
52100
}
53101

54102
#[tokio::test]
55103
async fn test_mode_time64() {
56-
let sql = "SELECT MODE(time64_col) FROM test_table";
57-
let batches = run_query(sql).await.unwrap();
58-
assert_eq!(
59-
display_val(batches).await,
60-
(DataType::Time64(TimeUnit::Microsecond), "03:00:00".to_string())
61-
);
104+
let mut execution = TestExecution::new().await.unwrap().with_setup(TEST_TABLE).await;
105+
106+
let actual = execution
107+
.run_and_format("SELECT MODE(time64_col) FROM test_table")
108+
.await;
109+
110+
insta::assert_yaml_snapshot!(actual, @r###"
111+
- +-----------------------------+
112+
- "| mode(test_table.time64_col) |"
113+
- +-----------------------------+
114+
- "| 03:00:00 |"
115+
- +-----------------------------+
116+
"###);
62117
}

tests/utils/mod.rs

Lines changed: 40 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -15,113 +15,57 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18-
use std::sync::Arc;
19-
20-
use arrow::array::{Date64Array, Float64Array, Time64MicrosecondArray};
21-
use arrow::datatypes::TimeUnit;
22-
use datafusion::arrow::array::{ArrayRef, Int64Array};
23-
use datafusion::arrow::datatypes::{DataType, Field, Schema};
24-
use datafusion::arrow::util::display::{ArrayFormatter, FormatOptions};
25-
use datafusion::arrow::{array::StringArray, record_batch::RecordBatch};
18+
use arrow::record_batch::RecordBatch;
19+
use arrow::util::pretty::pretty_format_batches;
2620
use datafusion::error::Result;
2721
use datafusion::execution::context::SessionContext;
2822
use datafusion::prelude::SessionConfig;
23+
use datafusion::sql::parser::DFParser;
2924
use datafusion_functions_extra::register_all_extra_functions;
25+
use log::debug;
3026

31-
// TODO: It would be great to release `datafusion-sqllogictest` as a crate.
32-
// This would allow easy integration and testing of SQL queries across projects.
33-
pub async fn create_context() -> Result<SessionContext> {
34-
let config = SessionConfig::new();
35-
let mut ctx = SessionContext::new_with_config(config);
36-
register_all_extra_functions(&mut ctx)?;
37-
Ok(ctx)
27+
pub struct TestExecution {
28+
ctx: SessionContext,
3829
}
3930

40-
async fn create_test_table() -> Result<SessionContext> {
41-
let ctx = create_context().await?;
42-
43-
let schema = Arc::new(Schema::new(vec![
44-
Field::new("utf8_col", DataType::Utf8, true),
45-
Field::new("int64_col", DataType::Int64, true),
46-
Field::new("float64_col", DataType::Float64, true),
47-
Field::new("date64_col", DataType::Date64, true),
48-
Field::new("time64_col", DataType::Time64(TimeUnit::Microsecond), true),
49-
]));
50-
51-
let utf8_values: ArrayRef = Arc::new(StringArray::from(vec![
52-
Some("apple"),
53-
Some("banana"),
54-
Some("apple"),
55-
Some("orange"),
56-
Some("banana"),
57-
Some("apple"),
58-
None,
59-
]));
60-
61-
let int64_values: ArrayRef = Arc::new(Int64Array::from(vec![
62-
Some(1),
63-
Some(2),
64-
Some(2),
65-
Some(3),
66-
Some(3),
67-
Some(3),
68-
None,
69-
]));
31+
impl TestExecution {
32+
pub async fn new() -> Result<Self> {
33+
let config = SessionConfig::new();
34+
let mut ctx = SessionContext::new_with_config(config);
35+
register_all_extra_functions(&mut ctx)?;
36+
Ok(Self { ctx })
37+
}
7038

71-
let float64_values: ArrayRef = Arc::new(Float64Array::from(vec![
72-
Some(1.0),
73-
Some(2.0),
74-
Some(2.0),
75-
Some(3.0),
76-
Some(3.0),
77-
Some(3.0),
78-
None,
79-
]));
39+
pub async fn with_setup(self, sql: &str) -> Self {
40+
debug!("Running setup query: {sql}");
41+
let statements = DFParser::parse_sql(sql).expect("Error parsing setup query");
42+
for statement in statements {
43+
debug!("Running setup statement: {statement}");
44+
let statement_sql = statement.to_string();
45+
self.ctx
46+
.sql(&statement_sql)
47+
.await
48+
.expect("Error planning setup failed")
49+
.collect()
50+
.await
51+
.expect("Error executing setup query");
52+
}
53+
self
54+
}
8055

81-
let date64_values: ArrayRef = Arc::new(Date64Array::from(vec![
82-
Some(1609459200000),
83-
Some(1609545600000),
84-
Some(1609545600000),
85-
Some(1609632000000),
86-
Some(1609632000000),
87-
Some(1609632000000),
88-
None,
89-
]));
56+
pub async fn run(&mut self, sql: &str) -> Result<Vec<RecordBatch>> {
57+
debug!("Running query: {sql}");
58+
self.ctx.sql(sql).await?.collect().await
59+
}
9060

91-
let time64_values: ArrayRef = Arc::new(Time64MicrosecondArray::from(vec![
92-
Some(3600000000),
93-
Some(7200000000),
94-
Some(7200000000),
95-
Some(10800000000),
96-
Some(10800000000),
97-
Some(10800000000),
98-
None,
99-
]));
100-
101-
let batch = RecordBatch::try_new(
102-
schema.clone(),
103-
vec![utf8_values, int64_values, float64_values, date64_values, time64_values],
104-
)?;
105-
106-
ctx.register_batch("test_table", batch)?;
107-
108-
Ok(ctx)
61+
pub async fn run_and_format(&mut self, sql: &str) -> Vec<String> {
62+
let results = self.run(sql).await.expect("Error running query");
63+
format_results(&results)
64+
}
10965
}
11066

111-
pub async fn run_query(sql: &str) -> Result<Vec<RecordBatch>> {
112-
let ctx = create_test_table().await?;
113-
ctx.sql(sql).await?.collect().await
114-
}
67+
fn format_results(results: &[RecordBatch]) -> Vec<String> {
68+
let formatted = pretty_format_batches(results).unwrap().to_string();
11569

116-
pub async fn display_val(batch: Vec<RecordBatch>) -> (DataType, String) {
117-
assert_eq!(batch.len(), 1);
118-
let batch = batch.first().unwrap();
119-
assert_eq!(batch.num_rows(), 1);
120-
let schema = batch.schema();
121-
let schema_col = schema.field(0);
122-
let c = batch.column(0);
123-
let options = FormatOptions::default().with_display_error(true);
124-
let f = ArrayFormatter::try_new(c.as_ref(), &options).unwrap();
125-
let repr = f.value(0).try_to_string().unwrap();
126-
(schema_col.data_type().clone(), repr)
70+
formatted.lines().map(|s| s.to_string()).collect()
12771
}

0 commit comments

Comments
 (0)