/** * Copyright 2011-2017 Asakusa Framework Team. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.asakusafw.dmdl.directio.text.tabular; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.util.Scanner; import java.util.TimeZone; import java.util.function.Consumer; import java.util.zip.GZIPInputStream; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExternalResource; import com.asakusafw.dmdl.directio.common.driver.GeneratorTesterRoot; import com.asakusafw.dmdl.directio.text.mock.EmptyLineFilter; import com.asakusafw.dmdl.directio.text.mock.MockFieldAdapter; import com.asakusafw.dmdl.directio.text.mock.UpperCaseTransformer; import com.asakusafw.dmdl.java.emitter.driver.ObjectDriver; import com.asakusafw.runtime.directio.BinaryStreamFormat; import com.asakusafw.runtime.io.ModelInput; import com.asakusafw.runtime.io.ModelOutput; import com.asakusafw.runtime.value.BooleanOption; import com.asakusafw.runtime.value.ByteOption; import com.asakusafw.runtime.value.Date; import com.asakusafw.runtime.value.DateOption; import com.asakusafw.runtime.value.DateTime; import com.asakusafw.runtime.value.DateTimeOption; import com.asakusafw.runtime.value.DecimalOption; import com.asakusafw.runtime.value.DoubleOption; import com.asakusafw.runtime.value.FloatOption; import com.asakusafw.runtime.value.IntOption; import com.asakusafw.runtime.value.LongOption; import com.asakusafw.runtime.value.ShortOption; import com.asakusafw.runtime.value.StringOption; /** * Test for {@link TabularTextEmitter}. */ public class TabularTextEmitterTest extends GeneratorTesterRoot { /** * Escapes time zone. */ @Rule public final ExternalResource escapeTimeZone = new ExternalResource() { TimeZone escape; @Override protected void before() { escape = TimeZone.getDefault(); TimeZone.setDefault(TimeZone.getTimeZone("PST")); } @Override protected void after() { if (escape != null) { TimeZone.setDefault(escape); } } }; /** * Initializes the test. * @throws Exception if some errors were occurred */ @Before public void setUp() throws Exception { emitDrivers.add(new TabularTextEmitter()); emitDrivers.add(new ObjectDriver()); } /** * simple case. * @throws Exception if failed */ @Test public void simple() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = { value : TEXT; };", }); ModelWrapper model = loaded.newModel("Simple") .setOption("value", new StringOption("Hello, world!")); BinaryStreamFormat<?> support = (BinaryStreamFormat<?>) loaded.newObject("text", "SimpleTabularTextFormat"); assertThat(support.getSupportedType(), is((Object) model.unwrap().getClass())); assertThat(support.getMinimumFragmentSize(), is(not(-1L))); BinaryStreamFormat<Object> unsafe = unsafe(support); ByteArrayOutputStream output = new ByteArrayOutputStream(); try (ModelOutput<Object> writer = unsafe.createOutput(unsafe.getSupportedType(), "hello", output)) { writer.write(model.unwrap()); } assertThat(text(output), is("Hello, world!\n")); Object buffer = loaded.newModel("Simple").unwrap(); try (ModelInput<Object> reader = unsafe.createInput(unsafe.getSupportedType(), "hello", in(output))) { assertThat(reader.readTo(buffer), is(true)); assertThat(buffer, is(model.unwrap())); assertThat(reader.readTo(buffer), is(false)); } } /** * w/ multiple rows/cols. * @throws Exception if failed */ @Test public void multiple() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " a : TEXT;", " b : TEXT;", " c : TEXT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("0a")) .setOption("b", new StringOption("0b")) .setOption("c", new StringOption("0c")), loaded.newModel("Simple") .setOption("a", new StringOption("1a")) .setOption("b", new StringOption("1b")) .setOption("c", new StringOption("1c")), loaded.newModel("Simple") .setOption("a", new StringOption("2a")) .setOption("b", new StringOption("2b")) .setOption("c", new StringOption("2c"))); assertThat(text(contents), is("0a\t0b\t0c\n1a\t1b\t1c\n2a\t2b\t2c\n")); } /** * w/ {@code BOOLEAN} field. * @throws Exception if failed */ @Test public void type_boolean() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " a : BOOLEAN;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new BooleanOption(true))); assertThat(text(contents), is("true\n")); } /** * w/ {@code BYTE} field. * @throws Exception if failed */ @Test public void type_byte() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " a : BYTE;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new ByteOption((byte) 1))); assertThat(text(contents), is("1\n")); } /** * w/ {@code SHORT} field. * @throws Exception if failed */ @Test public void type_short() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " a : SHORT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new ShortOption((short) 1))); assertThat(text(contents), is("1\n")); } /** * w/ {@code INT} field. * @throws Exception if failed */ @Test public void type_int() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " a : INT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new IntOption(1))); assertThat(text(contents), is("1\n")); } /** * w/ {@code LONG} field. * @throws Exception if failed */ @Test public void type_long() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " a : LONG;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new LongOption(1))); assertThat(text(contents), is("1\n")); } /** * w/ {@code FLOAT} field. * @throws Exception if failed */ @Test public void type_float() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " a : FLOAT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new FloatOption(1))); assertThat(text(contents), is("1.0\n")); } /** * w/ {@code DOUBLE} field. * @throws Exception if failed */ @Test public void type_double() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " a : DOUBLE;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new DoubleOption(1))); assertThat(text(contents), is("1.0\n")); } /** * w/ {@code header}. * @throws Exception if failed */ @Test public void header() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " header = force,", ")", "simple = {", " a : TEXT;", " b : TEXT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("A")) .setOption("b", new StringOption("B"))); assertThat(text(contents), is("a\tb\nA\tB\n")); } /** * w/ {@code header}. * @throws Exception if failed */ @Test public void header_name() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " header = force,", ")", "simple = {", " @directio.text.field(name = 'H')", " a : TEXT;", " b : TEXT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("A")) .setOption("b", new StringOption("B"))); assertThat(text(contents), is("H\tb\nA\tB\n")); } /** * w/ {@code charset}. * @throws Exception if failed */ @Test public void charset() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " charset = 'UTF-16LE',", ")", "simple = {", " a : TEXT;", "};", }); BinaryStreamFormat<?> support = (BinaryStreamFormat<?>) loaded.newObject("text", "SimpleTabularTextFormat"); assertThat(support.getMinimumFragmentSize(), is(-1L)); ModelWrapper model = loaded.newModel("Simple") .setOption("a", new StringOption("Hello, world!")); byte[] contents = write(loaded, model); assertThat(new String(contents, StandardCharsets.UTF_16LE), is("Hello, world!\n")); } /** * w/ {@code compression}. * @throws Exception if failed */ @Test public void compression() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " compression = gzip,", ")", "simple = {", " a : TEXT;", "};", }); ModelWrapper model = loaded.newModel("Simple") .setOption("a", new StringOption("Hello, world!")); byte[] contents = write(loaded, model); ByteArrayInputStream input = new ByteArrayInputStream(contents); try (Scanner s = new Scanner(new GZIPInputStream(input), StandardCharsets.UTF_8.name())) { assertThat(s.hasNextLine(), is(true)); assertThat(s.nextLine(), is("Hello, world!")); assertThat(s.hasNextLine(), is(false)); } } /** * w/ {@code line_separator}. * @throws Exception if failed */ @Test public void line_separator() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " line_separator = windows,", ")", "simple = {", " a : TEXT;", "};", }); ModelWrapper model = loaded.newModel("Simple") .setOption("a", new StringOption("Hello, world!")); byte[] contents = restore(loaded, model); assertThat(text(contents), is("Hello, world!\r\n")); } /** * w/ {@code field_separator}. * @throws Exception if failed */ @Test public void field_separator() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " field_separator = ':',", ")", "simple = {", " a : TEXT;", " b : TEXT;", " c : TEXT;", "};", }); ModelWrapper model = loaded.newModel("Simple") .setOption("a", new StringOption("A")) .setOption("b", new StringOption("B")) .setOption("c", new StringOption("C")); byte[] contents = restore(loaded, model); assertThat(text(contents), is("A:B:C\n")); } /** * w/ {@code escape_sequence}. * @throws Exception if failed */ @Test public void escape_sequence() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " escape_character = '^',", " escape_sequence = {", " 't' : '\\t'", " },", ")", "simple = {", " a : TEXT;", " b : TEXT;", "};", }); ModelWrapper model = loaded.newModel("Simple") .setOption("a", new StringOption("A")) .setOption("b", new StringOption("B\tC")); byte[] contents = restore(loaded, model); assertThat(text(contents), is("A\tB^tC\n")); } /** * w/ empty {@code escape_sequence}. * @throws Exception if failed */ @Test public void escape_sequence_empty() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " escape_character = '^',", " escape_sequence = {},", ")", "simple = {", " a : TEXT;", " b : TEXT;", "};", }); ModelWrapper model = loaded.newModel("Simple") .setOption("a", new StringOption("A")) .setOption("b", new StringOption("B")); byte[] contents = restore(loaded, model); assertThat(text(contents), is("A\tB\n")); } /** * w/ {@code escape_sequence} includes {@code null}. * @throws Exception if failed */ @Test public void escape_sequence_null() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " escape_character = '^',", " escape_sequence = {", " 'N' : null", " },", ")", "simple = {", " a : TEXT;", "};", }); ModelWrapper model = loaded.newModel("Simple") .setOption("a", new StringOption()); byte[] contents = restore(loaded, model); assertThat(text(contents), is("^N\n")); } /** * w/ {@code escape_line_separator}. * @throws Exception if failed */ @Test public void escape_line_separator() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " escape_character = '^',", " escape_line_separator = true,", ")", "simple = {", " a : TEXT;", " b : TEXT;", "};", }); ModelWrapper model = loaded.newModel("Simple") .setOption("a", new StringOption("A")) .setOption("b", new StringOption("B\nC")); byte[] contents = restore(loaded, model); assertThat(text(contents), is("A\tB^\nC\n")); } /** * w/ {@code escape_line_separator}. * @throws Exception if failed */ @Test public void escape_line_separator_false() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " escape_character = '^',", " escape_line_separator = false,", ")", "simple = {", " a : TEXT;", "};", }); read("a^\nb\n".getBytes(StandardCharsets.UTF_8), loaded, loaded.newModel("Simple").setOption("a", new StringOption("a^")), loaded.newModel("Simple").setOption("a", new StringOption("b"))); } /** * w/ {@code input_transformer}. * @throws Exception if failed */ @Test public void input_transformer() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " input_transformer = '" + EmptyLineFilter.class.getName() + "'", ")", "simple = {", " a : TEXT;", "};", }); read(loaded, "\n\nHello, world!\n\n", wrapper -> { assertThat(wrapper.getOption("a"), is(new StringOption("Hello, world!"))); }); } /** * w/ {@code output_transformer}. * @throws Exception if failed */ @Test public void output_transformer() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " output_transformer = '" + UpperCaseTransformer.class.getName() + "'", ")", "simple = {", " a : TEXT;", "};", }); ModelWrapper model = loaded.newModel("Simple") .setOption("a", new StringOption("hello")); byte[] contents = write(loaded, model); assertThat(text(contents), is("HELLO\n")); } /** * w/ {@code on_less_input}. * @throws Exception if failed */ @Test public void on_less_input() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " on_less_input = report,", ")", "simple = {", " a : TEXT;", " b : TEXT;", "};", }); read(loaded, "Hello, world!\n", wrapper -> { assertThat(wrapper.getOption("a"), is(new StringOption("Hello, world!"))); assertThat(wrapper.getOption("b"), is(new StringOption())); }); } /** * w/ {@code on_more_input}. * @throws Exception if failed */ @Test public void on_more_input() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " on_more_input = report,", ")", "simple = {", " a : TEXT;", " b : TEXT;", "};", }); read(loaded, "A\tB\tEX\n", wrapper -> { assertThat(wrapper.getOption("a"), is(new StringOption("A"))); assertThat(wrapper.getOption("b"), is(new StringOption("B"))); }); } /** * w/ {@code trim_input}. * @throws Exception if failed */ @Test public void trim_input() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " trim_input = true,", ")", "simple = {", " a : TEXT;", " b : TEXT;", " c : TEXT;", "};", }); read(loaded, " A\tB \t C \n", wrapper -> { assertThat(wrapper.getOption("a"), is(new StringOption("A"))); assertThat(wrapper.getOption("b"), is(new StringOption("B"))); assertThat(wrapper.getOption("c"), is(new StringOption("C"))); }); } /** * w/ {@code trim_input}. * @throws Exception if failed */ @Test public void trim_input_field() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " a : TEXT;", " @directio.text.field(trim_input = true)", " b : TEXT;", " c : TEXT;", "};", }); read(loaded, " A \t B \t C \n", wrapper -> { assertThat(wrapper.getOption("a"), is(new StringOption(" A "))); assertThat(wrapper.getOption("b"), is(new StringOption("B"))); assertThat(wrapper.getOption("c"), is(new StringOption(" C "))); }); } /** * w/ {@code skip_empty_input}. * @throws Exception if failed */ @Test public void skip_empty_input() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " skip_empty_input = true,", ")", "simple = {", " a : TEXT;", " b : TEXT;", "};", }); read(loaded, "\tA\t\tB\t\n", w -> { assertThat(w.getOption("a"), is(new StringOption("A"))); assertThat(w.getOption("b"), is(new StringOption("B"))); }); } /** * w/ {@code skip_empty_input}. * @throws Exception if failed */ @Test public void skip_empty_input_field() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.field(skip_empty_input = true)", " a : TEXT;", " b : TEXT;", " c : TEXT;", "};", }); read(loaded, "\tA\t\tB\n", wrapper -> { assertThat(wrapper.getOption("a"), is(new StringOption("A"))); assertThat(wrapper.getOption("b"), is(new StringOption(""))); assertThat(wrapper.getOption("c"), is(new StringOption("B"))); }); } /** * w/ {@code on_malformed_input}. * @throws Exception if failed */ @Test public void on_malformed_input() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " on_malformed_input = report,", ")", "simple = {", " a : TEXT;", " b : INT;", " c : TEXT;", "};", }); read(loaded, "A\tB\tC\n", wrapper -> { assertThat(wrapper.getOption("a"), is(new StringOption("A"))); assertThat(wrapper.getOption("b"), is(new IntOption())); assertThat(wrapper.getOption("c"), is(new StringOption("C"))); }); } /** * w/ {@code on_malformed_input}. * @throws Exception if failed */ @Test public void on_malformed_input_field() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.field(on_malformed_input = report)", " a : INT;", " b : INT;", "};", }); read(loaded, "INVALID\t1\n", wrapper -> { assertThat(wrapper.getOption("a"), is(new IntOption())); assertThat(wrapper.getOption("b"), is(new IntOption(1))); }); readError(loaded, "0\tINVALID\n"); } /** * w/ {@code on_unmappable_output}. * @throws Exception if failed */ @Test public void on_unmappable_output() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " on_unmappable_output = report,", ")", "simple = {", " a : TEXT;", "};", }); byte[] written = write(loaded, loaded.newModel("Simple") .setOption("a", new StringOption())); assertThat(text(written), is("\n")); } /** * w/ {@code on_unmappable_output}. * @throws Exception if failed */ @Test public void on_unmappable_output_field() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.field(on_unmappable_output = report)", " a : INT;", " b : INT;", "};", }); byte[] written = write(loaded, loaded.newModel("Simple") .setOption("a", new IntOption()) .setOption("b", new IntOption(1))); assertThat(text(written), is("\t1\n")); writeError(loaded, loaded.newModel("Simple") .setOption("a", new IntOption(0)) .setOption("b", new IntOption())); } /** * w/ {@code null_format}. * @throws Exception if failed */ @Test public void null_format() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " null_format = 'OK',", ")", "simple = {", " a : TEXT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new StringOption())); assertThat(text(contents), is("OK\n")); } /** * w/ {@code null_format}. * @throws Exception if failed */ @Test public void null_format_field() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " null_format = 'OK',", ")", "simple = {", " @directio.text.field(null_format = 'NULL')", " a : TEXT;", " b : TEXT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new StringOption()) .setOption("b", new StringOption())); assertThat(text(contents), is("NULL\tOK\n")); } /** * w/ {@code null_format}. * @throws Exception if failed */ @Test public void null_format_field_null() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " null_format = 'OK',", ")", "simple = {", " @directio.text.field(null_format = null)", " a : TEXT;", "};", }); writeError(loaded, loaded.newModel("Simple") .setOption("a", new StringOption())); } /** * w/ {@code true_format}. * @throws Exception if failed */ @Test public void true_format() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " true_format = 'A',", ")", "simple = {", " a : BOOLEAN;", " b : BOOLEAN;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new BooleanOption(true)) .setOption("b", new BooleanOption(false))); assertThat(text(contents), is("A\tfalse\n")); } /** * w/ {@code true_format}. * @throws Exception if failed */ @Test public void true_format_field() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " true_format = 'A',", ")", "simple = {", " @directio.text.field(true_format = '_')", " a : BOOLEAN;", " b : BOOLEAN;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new BooleanOption(true)) .setOption("b", new BooleanOption(true))); assertThat(text(contents), is("_\tA\n")); } /** * w/ {@code true_format}. * @throws Exception if failed */ @Test public void true_format_inconsistent_type() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.field(true_format = '_')", " a : TEXT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("Hello, world!"))); assertThat(text(contents), is("Hello, world!\n")); } /** * w/ {@code false_format}. * @throws Exception if failed */ @Test public void false_format() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " false_format = 'B',", ")", "simple = {", " a : BOOLEAN;", " b : BOOLEAN;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new BooleanOption(true)) .setOption("b", new BooleanOption(false))); assertThat(text(contents), is("true\tB\n")); } /** * w/ {@code false_format}. * @throws Exception if failed */ @Test public void false_format_field() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " false_format = 'B',", ")", "simple = {", " @directio.text.field(false_format = '_')", " a : BOOLEAN;", " b : BOOLEAN;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new BooleanOption(false)) .setOption("b", new BooleanOption(false))); assertThat(text(contents), is("_\tB\n")); } /** * w/ {@code false_format}. * @throws Exception if failed */ @Test public void false_format_inconsistent_type() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.field(false_format = '_')", " a : TEXT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("Hello, world!"))); assertThat(text(contents), is("Hello, world!\n")); } /** * w/ {@code number_format}. * @throws Exception if failed */ @Test public void number_format() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " number_format = '0.00',", ")", "simple = {", " a : DECIMAL;", "};", }); byte[] contents = write(loaded, loaded.newModel("Simple") .setOption("a", new DecimalOption(new BigDecimal("3.1415")))); read(contents, loaded, loaded.newModel("Simple") .setOption("a", new DecimalOption(new BigDecimal("3.14")))); assertThat(text(contents), is("3.14\n")); } /** * w/ {@code number_format}. * @throws Exception if failed */ @Test public void number_format_integer() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " number_format = '#,###;(#,###)',", ")", "simple = {", " a : INT;", " b : INT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new IntOption(12_345_678)) .setOption("b", new IntOption(-12_345))); assertThat(text(contents), is("12,345,678\t(12,345)\n")); } /** * w/ {@code number_format} for fields. * @throws Exception if failed */ @Test public void number_format_field() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " number_format = '0',", ")", "simple = {", " a : INT;", " @directio.text.field(number_format = '#,###')", " b : INT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new IntOption(12_345_678)) .setOption("b", new IntOption(-12_345))); assertThat(text(contents), is("12345678\t-12,345\n")); } /** * w/ {@code number_format} for fields. * @throws Exception if failed */ @Test public void number_format_field_null() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " number_format = '#,###',", ")", "simple = {", " a : INT;", " @directio.text.field(number_format = null)", " b : INT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new IntOption(12_345_678)) .setOption("b", new IntOption(-12_345))); assertThat(text(contents), is("12,345,678\t-12345\n")); } /** * w/ {@code false_format}. * @throws Exception if failed */ @Test public void number_format_inconsistent_type() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.field(number_format = '#,###')", " a : TEXT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("Hello, world!"))); assertThat(text(contents), is("Hello, world!\n")); } /** * w/ {@code date_format}. * @throws Exception if failed */ @Test public void date_format() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " date_format = 'yyyy_MM_dd',", ")", "simple = {", " a : DATE;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new DateOption(new Date(2017, 1, 6)))); assertThat(text(contents), is("2017_01_06\n")); } /** * w/ {@code date_format}. * @throws Exception if failed */ @Test public void date_format_field() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.field(date_format = 'yyyy_MM_dd')", " a : DATE;", " b : DATE;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new DateOption(new Date(2017, 1, 6))) .setOption("b", new DateOption(new Date(2017, 1, 6)))); assertThat(text(contents), is("2017_01_06\t2017-01-06\n")); } /** * w/ {@code datetime_format}. * @throws Exception if failed */ @Test public void datetime_format() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " datetime_format = 'yyyy_MM_dd HH-mm-ss',", ")", "simple = {", " a : DATETIME;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new DateTimeOption(new DateTime(2017, 1, 6, 22, 10, 0)))); assertThat(text(contents), is("2017_01_06 22-10-00\n")); } /** * w/ {@code datetime_format}. * @throws Exception if failed */ @Test public void datetime_format_field() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.field(datetime_format = 'yyyy_MM_dd HH-mm-ss')", " a : DATETIME;", " b : DATETIME;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new DateTimeOption(new DateTime(2017, 1, 6, 22, 10, 0))) .setOption("b", new DateTimeOption(new DateTime(2017, 1, 6, 22, 10, 0)))); assertThat(text(contents), is("2017_01_06 22-10-00\t2017-01-06 22:10:00\n")); } /** * w/ {@code datetime_format}. * @throws Exception if failed */ @Test public void datetime_format_inconsistent_type() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.field(datetime_format = '_')", " a : TEXT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("Hello, world!"))); assertThat(text(contents), is("Hello, world!\n")); } /** * w/ {@code timezone}. * @throws Exception if failed */ @Test public void timezone() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " timezone = 'UTC',", ")", "simple = {", " a : DATETIME;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new DateTimeOption(new DateTime(2017, 1, 2, 12, 34, 56)))); assertThat(text(contents), is("2017-01-02 20:34:56\n")); } /** * w/ {@code timezone}. * @throws Exception if failed */ @Test public void timezone_field() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " a : DATETIME;", " @directio.text.field(timezone = 'UTC')", " b : DATETIME;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new DateTimeOption(new DateTime(2017, 1, 2, 12, 34, 56))) .setOption("b", new DateTimeOption(new DateTime(2017, 1, 2, 12, 34, 56)))); assertThat(text(contents), is("2017-01-02 12:34:56\t2017-01-02 20:34:56\n")); } /** * w/ {@code timezone}. * @throws Exception if failed */ @Test public void timezone_null() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " timezone = 'UTC',", ")", "simple = {", " @directio.text.field(timezone = null)", " a : DATETIME;", " b : DATETIME;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new DateTimeOption(new DateTime(2017, 1, 2, 12, 34, 56))) .setOption("b", new DateTimeOption(new DateTime(2017, 1, 2, 12, 34, 56)))); assertThat(text(contents), is("2017-01-02 12:34:56\t2017-01-02 20:34:56\n")); } /** * w/ {@code timezone} for non datetime field. * @throws Exception if failed */ @Test public void timezone_inconsistent_type() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.field(timezone = 'UTC')", " a : TEXT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("Hello, world!"))); assertThat(text(contents), is("Hello, world!\n")); } /** * w/ {@code decimal_output_style}. * @throws Exception if failed */ @Test public void decimal_output_style() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " decimal_output_style = plain,", ")", "simple = {", " a : DECIMAL;", "};", }); ModelWrapper model = loaded.newModel("Simple") .setOption("a", new DecimalOption(new BigDecimal(BigInteger.valueOf(12), -10))); byte[] contents = write(loaded, model); assertThat(text(contents), is("120000000000\n")); } /** * w/ {@code decimal_output_style}. * @throws Exception if failed */ @Test public void decimal_output_style_field() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.field(decimal_output_style = plain)", " a : DECIMAL;", " b : DECIMAL;", "};", }); ModelWrapper model = loaded.newModel("Simple") .setOption("a", new DecimalOption(new BigDecimal(BigInteger.valueOf(12), -10))) .setOption("b", new DecimalOption(new BigDecimal(BigInteger.valueOf(12), -10))); byte[] contents = write(loaded, model); assertThat(text(contents), is("120000000000\t1.2E+11\n")); } /** * w/ {@code decimal_output_style}. * @throws Exception if failed */ @Test public void decimal_output_style_inconsistent_type() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.field(decimal_output_style = plain)", " a : TEXT;", "};", }); byte[] contents = restore(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("Hello, world!"))); assertThat(text(contents), is("Hello, world!\n")); } /** * w/ {@code adapter}. * @throws Exception if failed */ @Test public void adapter() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " adapter = '" + MockFieldAdapter.class.getName() + "'", ")", "simple = {", " a : TEXT;", "};", }); ModelWrapper model = loaded.newModel("Simple") .setOption("a", new StringOption("hello")); byte[] contents = restore(loaded, model); assertThat(text(contents), is("HELLO\n")); } /** * w/ {@code adapter}. * @throws Exception if failed */ @Test public void adapter_field() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.field(adapter = '" + MockFieldAdapter.class.getName() + "')", " a : TEXT;", " b : TEXT;", "};", }); ModelWrapper model = loaded.newModel("Simple") .setOption("a", new StringOption("hello")) .setOption("b", new StringOption("hello")); byte[] contents = restore(loaded, model); assertThat(text(contents), is("HELLO\thello\n")); } /** * w/ {@code adapter}. * @throws Exception if failed */ @Test public void adapter_override() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " adapter = '" + MockFieldAdapter.class.getName() + "'", ")", "simple = {", " a : TEXT;", " @directio.text.field(adapter = null)", " b : TEXT;", "};", }); ModelWrapper model = loaded.newModel("Simple") .setOption("a", new StringOption("hello")) .setOption("b", new StringOption("hello")); byte[] contents = restore(loaded, model); assertThat(text(contents), is("HELLO\thello\n")); } /** * w/ {@code directio.text.field}. * @throws Exception if failed */ @Test public void field_field() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.field", " a : TEXT;", "};", }); BinaryStreamFormat<?> support = (BinaryStreamFormat<?>) loaded.newObject("text", "SimpleTabularTextFormat"); assertThat(support.getMinimumFragmentSize(), is(not(-1L))); byte[] contents = write(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("A"))); read(contents, loaded, loaded.newModel("Simple") .setOption("a", new StringOption("A"))); assertThat(text(contents), is("A\n")); } /** * w/ {@code directio.text.ignore}. * @throws Exception if failed */ @Test public void field_ignore() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " a : TEXT;", " @directio.text.ignore", " b : TEXT;", "};", }); BinaryStreamFormat<?> support = (BinaryStreamFormat<?>) loaded.newObject("text", "SimpleTabularTextFormat"); assertThat(support.getMinimumFragmentSize(), is(not(-1L))); byte[] contents = write(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("A")) .setOption("b", new StringOption("B"))); read(contents, loaded, loaded.newModel("Simple") .setOption("a", new StringOption("A")) .setOption("b", new StringOption())); assertThat(text(contents), is("A\n")); } /** * w/ {@code directio.text.file_name}. * @throws Exception if failed */ @Test public void field_file_name() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular", "simple = {", " a : TEXT;", " @directio.text.file_name", " b : TEXT;", "};", }); BinaryStreamFormat<?> support = (BinaryStreamFormat<?>) loaded.newObject("text", "SimpleTabularTextFormat"); assertThat(support.getMinimumFragmentSize(), is(not(-1L))); byte[] contents = write(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("A")) .setOption("b", new StringOption("B"))); read(contents, loaded, loaded.newModel("Simple") .setOption("a", new StringOption("A")) .setOption("b", new StringOption("testing"))); assertThat(text(contents), is("A\n")); } /** * w/ {@code directio.text.line_number}. * @throws Exception if failed */ @Test public void field_line_number() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " input_transformer = '" + EmptyLineFilter.class.getName() + "'", ")", "simple = {", " a : TEXT;", " @directio.text.line_number", " b : LONG;", "};", }); BinaryStreamFormat<?> support = (BinaryStreamFormat<?>) loaded.newObject("text", "SimpleTabularTextFormat"); assertThat(support.getMinimumFragmentSize(), is(-1L)); byte[] contents = write(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("A")) .setOption("b", new LongOption(-1))); assertThat(text(contents), is("A\n")); read(loaded, "\n\nHello, world!\n\n", wrapper -> { assertThat(wrapper.getOption("a"), is(new StringOption("Hello, world!"))); assertThat(wrapper.getOption("b"), is(new LongOption(3))); }); } /** * w/ {@code directio.text.line_number}. * @throws Exception if failed */ @Test public void field_line_number_int() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " input_transformer = '" + EmptyLineFilter.class.getName() + "'", ")", "simple = {", " a : TEXT;", " @directio.text.line_number", " b : INT;", "};", }); BinaryStreamFormat<?> support = (BinaryStreamFormat<?>) loaded.newObject("text", "SimpleTabularTextFormat"); assertThat(support.getMinimumFragmentSize(), is(-1L)); byte[] contents = write(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("A")) .setOption("b", new IntOption(-1))); assertThat(text(contents), is("A\n")); read(loaded, "\n\nHello, world!\n\n", wrapper -> { assertThat(wrapper.getOption("a"), is(new StringOption("Hello, world!"))); assertThat(wrapper.getOption("b"), is(new IntOption(3))); }); } /** * w/ {@code directio.text.record_number}. * @throws Exception if failed */ @Test public void field_record_number() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " input_transformer = '" + EmptyLineFilter.class.getName() + "'", ")", "simple = {", " a : TEXT;", " @directio.text.record_number", " b : LONG;", "};", }); BinaryStreamFormat<?> support = (BinaryStreamFormat<?>) loaded.newObject("text", "SimpleTabularTextFormat"); assertThat(support.getMinimumFragmentSize(), is(-1L)); byte[] contents = write(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("A")) .setOption("b", new LongOption(-1))); assertThat(text(contents), is("A\n")); read(loaded, "\n\nHello, world!\n\n", wrapper -> { assertThat(wrapper.getOption("a"), is(new StringOption("Hello, world!"))); assertThat(wrapper.getOption("b"), is(new LongOption(1))); }); } /** * w/ {@code directio.text.record_number}. * @throws Exception if failed */ @Test public void field_record_number_int() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " input_transformer = '" + EmptyLineFilter.class.getName() + "'", ")", "simple = {", " a : TEXT;", " @directio.text.record_number", " b : INT;", "};", }); BinaryStreamFormat<?> support = (BinaryStreamFormat<?>) loaded.newObject("text", "SimpleTabularTextFormat"); assertThat(support.getMinimumFragmentSize(), is(-1L)); byte[] contents = write(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("A")) .setOption("b", new IntOption(-1))); assertThat(text(contents), is("A\n")); read(loaded, "\n\nHello, world!\n\n", wrapper -> { assertThat(wrapper.getOption("a"), is(new StringOption("Hello, world!"))); assertThat(wrapper.getOption("b"), is(new IntOption(1))); }); } /** * escape sequence contains duplicated keys. * @throws Exception if failed */ @Test public void escape_conflict_key() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " escape_character = '^',", " escape_sequence = {", " 'a' : 'A',", " 'a' : 'B',", " },", ")", "simple = {", " a : TEXT;", " b : TEXT;", "};", }); byte[] contents = write(loaded, loaded.newModel("Simple") .setOption("a", new StringOption("1-A")) .setOption("b", new StringOption("2-B"))); assertThat(text(contents), is("1-^a\t2-^a\n")); } /** * escape sequence contains duplicated values. * @throws Exception if failed */ @Test public void escape_conflict_value() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " escape_character = '^',", " escape_sequence = {", " 'a' : 'A',", " 'b' : 'A',", " },", ")", "simple = {", " a : TEXT;", " b : TEXT;", "};", }); read(loaded, "1-^a\t2-^b\n", wrapper -> { assertThat(wrapper.getOption("a"), is(new StringOption("1-A"))); assertThat(wrapper.getOption("b"), is(new StringOption("2-A"))); }); } /** * escape sequence contains duplicated values. * @throws Exception if failed */ @Test public void escape_conflict_null() throws Exception { ModelLoader loaded = generateJavaFromLines(new String[] { "@directio.text.tabular(", " escape_character = '^',", " escape_sequence = {", " 'a' : null,", " 'b' : null,", " },", ")", "simple = {", " a : TEXT;", " b : TEXT;", "};", }); read(loaded, "^a\t^b\n", wrapper -> { assertThat(wrapper.getOption("a"), is(new StringOption())); assertThat(wrapper.getOption("b"), is(new StringOption())); }); } /** * w/ unknown property. * @throws Exception if failed */ @Test public void invalid_unknown_property() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " undef = true,", ")", "simple = {", " a : TEXT;", "};", }); } /** * w/ unknown charset. * @throws Exception if failed */ @Test public void invalid_charset_unknown() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " charset = '?',", ")", "simple = {", " a : TEXT;", "};", }); } /** * w/ unknown header. * @throws Exception if failed */ @Test public void invalid_header_unknown() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " header = '?',", ")", "simple = {", " a : TEXT;", "};", }); } /** * w/ unknown compression. * @throws Exception if failed */ @Test public void invalid_compression_unknown() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " compression = '?',", ")", "simple = {", " a : TEXT;", "};", }); } /** * w/ unknown line_separator. * @throws Exception if failed */ @Test public void invalid_line_separator_unknown() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " line_separator = '\\n',", ")", "simple = {", " a : TEXT;", "};", }); } /** * w/ malformed field_separator. * @throws Exception if failed */ @Test public void invalid_field_separator_malformed() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " field_separator = '<>',", ")", "simple = {", " a : TEXT;", "};", }); } /** * field_separator conflict w/ line separator. * @throws Exception if failed */ @Test public void invalid_field_separator_conflict() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " field_separator = '\\r',", ")", "simple = {", " a : TEXT;", "};", }); shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " field_separator = '\\n',", ")", "simple = {", " a : TEXT;", "};", }); } /** * w/ malformed escape_character. * @throws Exception if failed */ @Test public void invalid_escape_character_malformed() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " escape_character = '<>',", ")", "simple = {", " a : TEXT;", "};", }); } /** * w/ malformed escape_line_separator. * @throws Exception if failed */ @Test public void invalid_escape_line_separator_malformed() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " escape_line_separator = unknown,", ")", "simple = {", " a : TEXT;", "};", }); } /** * escape_character conflict w/ line separator. * @throws Exception if failed */ @Test public void invalid_escape_character_conflict_line_separator() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " escape_character = '\\r',", ")", "simple = {", " a : TEXT;", "};", }); shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " escape_character = '\\n',", ")", "simple = {", " a : TEXT;", "};", }); } /** * escape_character conflict w/ line separator. * @throws Exception if failed */ @Test public void invalid_escape_character_conflict_field_separator() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " field_separator = ':',", " escape_character = ':',", ")", "simple = {", " a : TEXT;", "};", }); shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " escape_character = '\\t',", ")", "simple = {", " a : TEXT;", "};", }); } /** * w/ malformed escape_sequence. * @throws Exception if failed */ @Test public void invalid_escape_sequence_malformed() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " escape_character = '^',", " escape_sequence = { 'n', '\\n' },", ")", "simple = {", " a : TEXT;", "};", }); } /** * escape_sequence w/ malformed key. * @throws Exception if failed */ @Test public void invalid_escape_sequence_malformed_key() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " escape_character = '^',", " escape_sequence = {", " 'malformed' : '\\n'", " },", ")", "simple = {", " a : TEXT;", "};", }); } /** * escape_sequence w/ malformed value. * @throws Exception if failed */ @Test public void invalid_escape_sequence_malformed_value() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " escape_character = '^',", " escape_sequence = {", " 'n' : '\\r\\n'", " },", ")", "simple = {", " a : TEXT;", "};", }); } /** * escape_sequence conflict w/ line separators. * @throws Exception if failed */ @Test public void invalid_escape_sequence_conflict_line_separator() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " escape_character = '^',", " escape_sequence = {", " '\\n' : '\\n'", " },", ")", "simple = {", " a : TEXT;", "};", }); shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " escape_character = '^',", " escape_sequence = {", " '\\r' : '\\r'", " },", ")", "simple = {", " a : TEXT;", "};", }); } /** * escape_sequence w/o escape character. * @throws Exception if failed */ @Test public void invalid_escape_sequence_without_escape_character() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " escape_sequence = {", " 'N' : null", " },", ")", "simple = {", " a : TEXT;", "};", }); } /** * escape_line_separator w/o escape character. * @throws Exception if failed */ @Test public void invalid_escape_line_separator_without_escape_character() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " escape_line_separator = true,", ")", "simple = {", " a : TEXT;", "};", }); } /** * w/ malformed null_format. * @throws Exception if failed */ @Test public void invalid_null_format_malformed() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " null_format = {},", ")", "simple = {", " a : TEXT;", "};", }); } /** * w/ malformed true_format. * @throws Exception if failed */ @Test public void invalid_true_format_malformed() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " true_format = {},", ")", "simple = {", " a : TEXT;", "};", }); } /** * true_format conflict w/ null_format. * @throws Exception if failed */ @Test public void invalid_true_format_conflict_null_format() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " null_format = 'NULL',", " true_format = 'NULL',", ")", "simple = {", " a : TEXT;", "};", }); } /** * true_format conflict w/ null_format. * @throws Exception if failed */ @Test public void invalid_true_format_conflict_null_format_inherited() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " null_format = 'a',", ")", "simple = {", " @directio.text.field(true_format = 'a')", " a : BOOLEAN;", "};", }); } /** * w/ malformed false_format. * @throws Exception if failed */ @Test public void invalid_false_format_malformed() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " false_format = {},", ")", "simple = {", " a : TEXT;", "};", }); } /** * false_format conflict w/ null_format. * @throws Exception if failed */ @Test public void invalid_false_format_conflict_null_format() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " null_format = 'NULL',", " false_format = 'NULL',", ")", "simple = {", " a : TEXT;", "};", }); } /** * false_format conflict w/ true_format. * @throws Exception if failed */ @Test public void invalid_false_format_conflict_true_format() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " true_format = '_',", " false_format = '_',", ")", "simple = {", " a : TEXT;", "};", }); } /** * false_format conflict w/ null_format. * @throws Exception if failed */ @Test public void invalid_false_format_conflict_null_format_inherited() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " null_format = 'a',", ")", "simple = {", " @directio.text.field(false_format = 'a')", " a : BOOLEAN;", "};", }); } /** * false_format conflict w/ true_format. * @throws Exception if failed */ @Test public void invalid_false_format_conflict_true_format_inherited() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " true_format = 'a',", ")", "simple = {", " @directio.text.field(false_format = 'a')", " a : BOOLEAN;", "};", }); } /** * malformed number_format. * @throws Exception if failed */ @Test public void invalid_number_format_malformed() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " number_format = 'Hello, world!',", ")", "simple = {", " a : TEXT;", "};", }); } /** * malformed date_format. * @throws Exception if failed */ @Test public void invalid_date_format_malformed() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " date_format = 'Hello, world!',", ")", "simple = {", " a : TEXT;", "};", }); } /** * malformed datetime_format. * @throws Exception if failed */ @Test public void invalid_datetime_format_malformed() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " datetime_format = 'Hello, world!',", ")", "simple = {", " a : TEXT;", "};", }); } /** * malformed timezone. * @throws Exception if failed */ @Test public void invalid_timezone_malformed() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular(", " timezone = 'Hello, world!',", ")", "simple = {", " a : TEXT;", "};", }); } /** * w/o valid fields. * @throws Exception if failed */ @Test public void invalid_field_empty() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.ignore", " a : TEXT;", "};", }); } /** * conflict field attributes. * @throws Exception if failed */ @Test public void invalid_field_conflict() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.field", " @directio.text.ignore", " a : TEXT;", "};", }); } /** * field w/ unknown property. * @throws Exception if failed */ @Test public void invalid_field_unknown() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.field(undef = '?')", " a : TEXT;", "};", }); } /** * file_name field w/ inconsistent type. * @throws Exception if failed */ @Test public void invalid_field_file_name_inconsistent_type() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.file_name", " a : INT;", " b : TEXT;", "};", }); } /** * line_number field w/ inconsistent type. * @throws Exception if failed */ @Test public void invalid_field_line_number_inconsistent_type() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.line_number", " a : TEXT;", " b : TEXT;", "};", }); } /** * record_number field w/ inconsistent type. * @throws Exception if failed */ @Test public void invalid_field_record_number_inconsistent_type() throws Exception { shouldSemanticErrorFromLines(new String[] { "@directio.text.tabular", "simple = {", " @directio.text.record_number", " a : TEXT;", " b : TEXT;", "};", }); } private byte[] write(ModelLoader loaded, ModelWrapper... objects) { String name = objects[0].getModelClass().getSimpleName(); BinaryStreamFormat<Object> unsafe = unsafe(loaded.newObject("text", name + "TabularTextFormat")); ByteArrayOutputStream output = new ByteArrayOutputStream(); try (ModelOutput<Object> writer = unsafe.createOutput(unsafe.getSupportedType(), "testing", output)) { for (ModelWrapper object : objects) { writer.write(object.unwrap()); } } catch (IOException | InterruptedException e) { throw new AssertionError(e); } return output.toByteArray(); } private void writeError(ModelLoader loaded, ModelWrapper object) { String name = object.getModelClass().getSimpleName(); BinaryStreamFormat<Object> unsafe = unsafe(loaded.newObject("text", name + "TabularTextFormat")); ByteArrayOutputStream output = new ByteArrayOutputStream(); try (ModelOutput<Object> writer = unsafe.createOutput(unsafe.getSupportedType(), "testing", output)) { writer.write(object.unwrap()); fail(); } catch (IOException e) { // ok. } catch (InterruptedException e) { throw new AssertionError(e); } } private void read(ModelLoader loaded, String contents, Consumer<ModelWrapper> tester) { BinaryStreamFormat<Object> unsafe = unsafe(loaded.newObject("text", "SimpleTabularTextFormat")); ModelWrapper wrapper = loaded.newModel("Simple"); Object buffer = wrapper.unwrap(); try (ModelInput<Object> reader = unsafe.createInput(unsafe.getSupportedType(), "testing", in(contents))) { assertThat(reader.readTo(buffer), is(true)); tester.accept(wrapper); assertThat(reader.readTo(buffer), is(false)); } catch (IOException | InterruptedException e) { throw new AssertionError(e); } } private void read( byte[] contents, ModelLoader loaded, ModelWrapper... objects) throws IOException, InterruptedException { String name = objects[0].getModelClass().getSimpleName(); BinaryStreamFormat<Object> unsafe = unsafe(loaded.newObject("text", name + "TabularTextFormat")); Object buffer = loaded.newModel(name).unwrap(); try (ModelInput<Object> reader = unsafe.createInput(unsafe.getSupportedType(), "testing", new ByteArrayInputStream(contents))) { for (ModelWrapper object : objects) { assertThat(reader.readTo(buffer), is(true)); assertThat(buffer, is(object.unwrap())); } assertThat(reader.readTo(buffer), is(false)); } } private void readError(ModelLoader loaded, String contents) { BinaryStreamFormat<Object> unsafe = unsafe(loaded.newObject("text", "SimpleTabularTextFormat")); ModelWrapper wrapper = loaded.newModel("Simple"); Object buffer = wrapper.unwrap(); try (ModelInput<Object> reader = unsafe.createInput(unsafe.getSupportedType(), "testing", in(contents))) { reader.readTo(buffer); fail(); } catch (IOException e) { // ok. } catch (InterruptedException e1) { throw new AssertionError(e1); } } private byte[] restore(ModelLoader loaded, ModelWrapper... objects) throws IOException, InterruptedException { byte[] contents = write(loaded, objects); read(contents, loaded, objects); return contents; } @SuppressWarnings("unchecked") private BinaryStreamFormat<Object> unsafe(Object support) { return (BinaryStreamFormat<Object>) support; } private ByteArrayInputStream in(String contents) { return new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8)); } private ByteArrayInputStream in(ByteArrayOutputStream output) { return new ByteArrayInputStream(output.toByteArray()); } private String text(ByteArrayOutputStream output) { return text(output.toByteArray()); } private String text(byte[] contents) { return new String(contents, StandardCharsets.UTF_8); } }