diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..730cb5e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,48 @@ +name: CI + +on: + push: + pull_request: + +jobs: + test: + name: Test (Python ${{ matrix.python-version }}) + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12"] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install package + run: | + python -m pip install --upgrade pip + pip install -e . + + - name: Show version + run: | + tir-csv --version || true + + - name: Run tests + run: | + chmod +x tests/run.sh + tests/run.sh + + - name: Build package + run: | + pip install build + python -m build + + - name: Check package + run: | + pip install twine + twine check dist/* diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..2222f3e --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,30 @@ +name: Publish to PyPI + +on: + push: + tags: + - "v*" + +jobs: + publish: + runs-on: ubuntu-latest + + permissions: + id-token: write + contents: read + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.x" + + - run: | + python -m pip install --upgrade pip + pip install build + + - run: python -m build + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/README.md b/README.md index b47abaa..4294109 100644 --- a/README.md +++ b/README.md @@ -10,4 +10,7 @@ pip install tir-csv ## Usage -tir-csv parse file.csv +```bash +tir-csv parse file.csv > file.tir +tir-csv unparse file.csv < file.tir +``` diff --git a/pyproject.toml b/pyproject.toml index def1502..bcaedff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,16 +1,19 @@ -[build-system] -requires = ["setuptools>=61"] -build-backend = "setuptools.build_meta" - [project] name = "tir-csv" -version = "0.1.2" description = "CSV/TSV <-> TIR converter backend for tirenvi" readme = "README.md" requires-python = ">=3.9" license = { text = "MIT" } authors = [{ name = "OGAWA Keiji" }] dependencies = [] +scripts = { tir-csv = "tir_csv.cli:main" } + +dynamic = ["version"] + +[build-system] +requires = ["setuptools>=61", "setuptools_scm"] +build-backend = "setuptools.build_meta" -[project.scripts] -tir-csv = "tir_csv.cli:main" +[tool.setuptools_scm] +version_scheme = "no-guess-dev" +local_scheme = "no-local-version" diff --git a/src/tir_csv/parser.py b/src/tir_csv/parser.py index be6248d..1acd650 100755 --- a/src/tir_csv/parser.py +++ b/src/tir_csv/parser.py @@ -7,7 +7,6 @@ from typing import Optional from tir_csv.io_utils import input_stream_csv, output_stream_csv -__version__ = "0.1.2" FORMAT_VERSION = "tir/0.1" # ------------------------------------------------------------ @@ -79,6 +78,12 @@ def unparse(output_file_path: Optional[str], delimiter: str = ",") -> None: # utilities # ------------------------------------------------------------ +from importlib.metadata import version + + +def get_version(): + return version("tir-csv") + def normalize_cell(cell: str) -> str: return cell.replace("\r\n", "\n").replace("\r", "\n") @@ -86,7 +91,7 @@ def normalize_cell(cell: str) -> str: def usage() -> None: print( - f"""tir-csv {__version__} + f"""tir-csv {get_version()} usage: tir-csv parse [--delimiter DELIM] [file|-] @@ -143,7 +148,7 @@ def run(argv) -> int: return 1 if args[0] == "--version": - print(__version__) + print(get_version()) return 0 if len(args) not in (1, 2): diff --git a/tests/.gitignore b/tests/.gitignore index 01308b5..f68f03c 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,7 +1,8 @@ # --- Generated by test runner --- +!data/ # Actual output (never commit) -out-actual +out-actual.txt gen* diff-* diff --git a/tests/cases/check/rg_no_ascii/out-expected.txt b/tests/cases/check/rg_no_ascii/out-expected.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/cases/check/rg_no_ascii/run.sh b/tests/cases/check/rg_no_ascii/run.sh new file mode 100644 index 0000000..15d4a47 --- /dev/null +++ b/tests/cases/check/rg_no_ascii/run.sh @@ -0,0 +1,4 @@ +#!/bin/sh +set -eu + +rg -n -g '*.py' -g '*.sh' '[^\x00-\x7F]' $TIRENVI_ROOT > out-actual.txt \ No newline at end of file diff --git a/tests/cases/tir-csv/help/out-expected b/tests/cases/tir-csv/help/out-expected.txt similarity index 96% rename from tests/cases/tir-csv/help/out-expected rename to tests/cases/tir-csv/help/out-expected.txt index 78e70d3..66aea63 100644 --- a/tests/cases/tir-csv/help/out-expected +++ b/tests/cases/tir-csv/help/out-expected.txt @@ -1,5 +1,4 @@ unknown sub command: help -tir-csv 0.1.2 usage: tir-csv parse [--delimiter DELIM] [file|-] diff --git a/tests/cases/tir-csv/help/run.sh b/tests/cases/tir-csv/help/run.sh index c92fc9e..2f93870 100755 --- a/tests/cases/tir-csv/help/run.sh +++ b/tests/cases/tir-csv/help/run.sh @@ -1,6 +1,6 @@ #!/bin/sh # help set -u -exec > out-actual 2>&1 -tir-csv help \ No newline at end of file +tir-csv help > gen.txt 2>&1 +grep -vE '^tir-csv [0-9]' gen.txt > out-actual.txt || true \ No newline at end of file diff --git a/tests/cases/tir-csv/parse-file/out-expected b/tests/cases/tir-csv/parse-file/out-expected.txt similarity index 100% rename from tests/cases/tir-csv/parse-file/out-expected rename to tests/cases/tir-csv/parse-file/out-expected.txt diff --git a/tests/cases/tir-csv/parse-file/run.sh b/tests/cases/tir-csv/parse-file/run.sh index 8d1f52b..2e21586 100755 --- a/tests/cases/tir-csv/parse-file/run.sh +++ b/tests/cases/tir-csv/parse-file/run.sh @@ -2,7 +2,7 @@ # Test that newline and tab characters are correctly converted to \n and \t # When a file name is specified, the absolute path of the file is output set -eu -exec > out-actual 2>&1 +exec > out-actual.txt 2>&1 # tir-csv parse "$TIRENVI_ROOT/tests/data/complex.csv" | sed "s|$TIRENVI_ROOT|/|g" diff --git a/tests/cases/tir-csv/parse-stdin/out-expected b/tests/cases/tir-csv/parse-stdin/out-expected.txt similarity index 100% rename from tests/cases/tir-csv/parse-stdin/out-expected rename to tests/cases/tir-csv/parse-stdin/out-expected.txt diff --git a/tests/cases/tir-csv/parse-stdin/run.sh b/tests/cases/tir-csv/parse-stdin/run.sh index 257526d..5f6af58 100755 --- a/tests/cases/tir-csv/parse-stdin/run.sh +++ b/tests/cases/tir-csv/parse-stdin/run.sh @@ -2,6 +2,6 @@ # When input is provided via stdin, the file name becomes null set -eu -exec > out-actual 2>&1 +exec > out-actual.txt 2>&1 tir-csv parse < "$TIRENVI_ROOT/tests/data/complex.csv" diff --git a/tests/cases/tir-csv/unparse/out-expected b/tests/cases/tir-csv/unparse/out-expected.txt similarity index 100% rename from tests/cases/tir-csv/unparse/out-expected rename to tests/cases/tir-csv/unparse/out-expected.txt diff --git a/tests/cases/tir-csv/unparse/run.sh b/tests/cases/tir-csv/unparse/run.sh index 1251f91..eab1c97 100755 --- a/tests/cases/tir-csv/unparse/run.sh +++ b/tests/cases/tir-csv/unparse/run.sh @@ -1,5 +1,5 @@ #!/bin/sh set -eu -exec > out-actual 2>&1 +exec > out-actual.txt 2>&1 tir-csv unparse < "$TIRENVI_ROOT/tests/data/complex.tir" diff --git a/tests/cases/tir-tsv/parse-file/out-expected b/tests/cases/tir-tsv/parse-file/out-expected.txt similarity index 100% rename from tests/cases/tir-tsv/parse-file/out-expected rename to tests/cases/tir-tsv/parse-file/out-expected.txt diff --git a/tests/cases/tir-tsv/parse-file/run.sh b/tests/cases/tir-tsv/parse-file/run.sh index fff2ad1..7ae179f 100755 --- a/tests/cases/tir-tsv/parse-file/run.sh +++ b/tests/cases/tir-tsv/parse-file/run.sh @@ -2,6 +2,6 @@ # Test that newline and tab characters are correctly converted to \n and \t # When a file name is specified, the absolute path of the file is output set -eu -exec > out-actual 2>&1 +exec > out-actual.txt 2>&1 tir-csv parse --delimiter "\t" "$TIRENVI_ROOT/tests/data/complex.tsv" | sed "s|$TIRENVI_ROOT|/|g" \ No newline at end of file diff --git a/tests/cases/tir-tsv/unparse/out-expected b/tests/cases/tir-tsv/unparse/out-expected.txt similarity index 100% rename from tests/cases/tir-tsv/unparse/out-expected rename to tests/cases/tir-tsv/unparse/out-expected.txt diff --git a/tests/cases/tir-tsv/unparse/run.sh b/tests/cases/tir-tsv/unparse/run.sh index 3043a7a..a2e8220 100755 --- a/tests/cases/tir-tsv/unparse/run.sh +++ b/tests/cases/tir-tsv/unparse/run.sh @@ -1,5 +1,5 @@ #!/bin/sh set -eu -exec > out-actual 2>&1 +exec > out-actual.txt 2>&1 tir-csv unparse --delimiter "\t" < "$TIRENVI_ROOT/tests/data/complex.tir" diff --git a/tests/data/complex.csv b/tests/data/complex.csv new file mode 100644 index 0000000..fe7a1c0 --- /dev/null +++ b/tests/data/complex.csv @@ -0,0 +1,115 @@ +A1,B22,C333,D4444,E55555,F666666 +alpha1,b2,c3,d4,e5,f6 + ===,- next -, line, has, no, value +,,,,, +x1,,y22,,z333, +===, - next -, line, has,linefeed, +" +""1""2h"", 34567890a",abc,DEF123," + + +",gh,9 +a,,"b +",,c, + ===,- next -, lines, has,tab, + l ongtext01,mi d2,s,tt,uuu,vvvv +,, , ,, +R1C1,R1C2,R1C3,R1C4,R1C5,R1C6 + ===,- next -, line, is,multibyte, value +aaあい,いろ2,ぼんさんが,へを,こいた,.!... +g1,h22,i333,j4444,k55555,l6 + ===,- next -, lines, has,linefeed+,tab + ," + ",n , o333,, +pqrst,uv,wx1,yz22,,345 +,,,,, +a1b2c3,,XYZ,7777,,k9 +short,longer12,x,yz,,end +,,,,, +row15a,row15b,row15c,row15d,row15e,row15f +1,22,333,4444,55555,666666 +alpha,beta,gamma,delta,epsilon,zeta +,,,,, +mix1,,mix3,444,,six6 +abc123,,def456,,ghi789, +z,,y,,x, +,,,,, +t1,t2,t3,t4,t5,t6 +r1c1,r1c2,,r1c4,,r1c6 +data1,data22,data333,data4444,data55555,data6 +,,,,, +A,B,C,D,E,F +abc,,123,,XYZ, +one1,two22,three3,four44,five5,six66 +,,,,, +r30a,r30b,r30c,r30d,r30e,r30f +longvalue1,mid,short,s,tt,uuu +,,,,, +x,y,z,,,end +abcde,fghij,klmno,pqrst,uvwxy,z +,,,,, +cell1,,cell3,,cell5, +111,2222,33333,444444,55,6 +,,,,, +row40a,row40b,row40c,row40d,row40e,row40f +a1,a2,a3,a4,a5,a6 +,,,,, +mixA,,mixC,DDD,,FFF +123abc,456def,,789ghi,,000 +,,,,, +r45a,r45b,r45c,r45d,r45e,r45f +alpha9,,beta8,,gamma7, +,,,,, +A1B2C3,D4E5F6,G7H8I9,J0,K1,L2 +short1,,short3,,short5, +,,,,, +r50a,r50b,r50c,r50d,r50e,r50f +x1y2,z3,,w4,,v5 +,,,,, +longertext,mid,small,s1,s22,s333 +,,,,, +r55a,r55b,r55c,r55d,r55e,r55f +abc,def,ghi,jkl,mno,pqr +,,,,, +1a,2b,3c,4d,5e,6f +,,,,, +row60a,row60b,row60c,row60d,row60e,row60f +value1,,value3,,value5, +,,,,, +aa,bb,cc,dd,ee,ff +,,,,, +r65a,r65b,r65c,r65d,r65e,r65f +x,,y,,z, +,,,,, +alpha01,beta02,gamma03,delta04,eps05,z6 +,,,,, +row70a,row70b,row70c,row70d,row70e,row70f +1,,3,,5, +,,,,, +abc1,def2,ghi3,jkl4,mno5,pqr6 +,,,,, +r75a,r75b,r75c,r75d,r75e,r75f +mix,,mix2,,mix3, +,,,,, +a,b,c,d,e,f +,,,,, +row80a,row80b,row80c,row80d,row80e,row80f +123,234,345,456,567,678 +,,,,, +Aaa,Bbb,Ccc,Ddd,Eee,Fff +,,,,, +r85a,r85b,r85c,r85d,r85e,r85f +x1,,x3,,x5, +,,,,, +abcde12345,f1,g2,h3,i4,j5 +,,,,, +row90a,row90b,row90c,row90d,row90e,row90f +1a2b3c,,4d5e6f,,7g8h9i, +,,,,, +short,,mid,,longer, +,,,,, +r95a,r95b,r95c,r95d,r95e,r95f +a1b,,c2d,,e3f, +,,,,, +end1,end2,end3,end4,end5,end6 +,,,,, diff --git a/tests/data/complex.tir b/tests/data/complex.tir new file mode 100644 index 0000000..620ab7d --- /dev/null +++ b/tests/data/complex.tir @@ -0,0 +1,110 @@ +{"kind": "file_attr", "version": "tir/0.1", "file_path": "//tests/data/complex.csv"} +{"kind": "grid", "row": ["A1", "B22", "C333", "D4444", "E55555", "F666666"]} +{"kind": "grid", "row": ["alpha1", "b2", "c3", "d4", "e5", "f6"]} +{"kind": "grid", "row": [" ===", "- next -", " line", " has", " no", " value "]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["x1", "", "y22", "", "z333", ""]} +{"kind": "grid", "row": ["===", " - next -", " line", " has", "linefeed", " "]} +{"kind": "grid", "row": ["\n\"1\"2h\", 34567890a", "abc", "DEF123", "\n\n\n", "gh", "9"]} +{"kind": "grid", "row": ["a", "", "b\n", "", "c", ""]} +{"kind": "grid", "row": [" ===", "- next -", " lines", " has", "tab", " "]} +{"kind": "grid", "row": ["\t l\tongtext01", "mi\t\td2", "s", "tt", "uuu", "vvvv"]} +{"kind": "grid", "row": ["", "", "\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t", "", ""]} +{"kind": "grid", "row": ["R1C1", "R1C2", "R1C3", "R1C4", "R1C5", "R1C6"]} +{"kind": "grid", "row": [" ===", "- next -", " line", " is", "multibyte", " value "]} +{"kind": "grid", "row": ["aaあい", "いろ2", "ぼんさんが", "へを", "こいた", ".!..."]} +{"kind": "grid", "row": ["g1", "h22", "i333", "j4444", "k55555", "l6"]} +{"kind": "grid", "row": [" ===", "- next -", " lines", " has", "linefeed+", "tab "]} +{"kind": "grid", "row": ["\t\t ", "\n\t", "n\t ", "\t\t o333", "", ""]} +{"kind": "grid", "row": ["pqrst", "uv", "wx1", "yz22", "", "345"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["a1b2c3", "", "XYZ", "7777", "", "k9"]} +{"kind": "grid", "row": ["short", "longer12", "x", "yz", "", "end"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["row15a", "row15b", "row15c", "row15d", "row15e", "row15f"]} +{"kind": "grid", "row": ["1", "22", "333", "4444", "55555", "666666"]} +{"kind": "grid", "row": ["alpha", "beta", "gamma", "delta", "epsilon", "zeta"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["mix1", "", "mix3", "444", "", "six6"]} +{"kind": "grid", "row": ["abc123", "", "def456", "", "ghi789", ""]} +{"kind": "grid", "row": ["z", "", "y", "", "x", ""]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["t1", "t2", "t3", "t4", "t5", "t6"]} +{"kind": "grid", "row": ["r1c1", "r1c2", "", "r1c4", "", "r1c6"]} +{"kind": "grid", "row": ["data1", "data22", "data333", "data4444", "data55555", "data6"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["A", "B", "C", "D", "E", "F"]} +{"kind": "grid", "row": ["abc", "", "123", "", "XYZ", ""]} +{"kind": "grid", "row": ["one1", "two22", "three3", "four44", "five5", "six66"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["r30a", "r30b", "r30c", "r30d", "r30e", "r30f"]} +{"kind": "grid", "row": ["longvalue1", "mid", "short", "s", "tt", "uuu"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["x", "y", "z", "", "", "end"]} +{"kind": "grid", "row": ["abcde", "fghij", "klmno", "pqrst", "uvwxy", "z"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["cell1", "", "cell3", "", "cell5", ""]} +{"kind": "grid", "row": ["111", "2222", "33333", "444444", "55", "6"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["row40a", "row40b", "row40c", "row40d", "row40e", "row40f"]} +{"kind": "grid", "row": ["a1", "a2", "a3", "a4", "a5", "a6"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["mixA", "", "mixC", "DDD", "", "FFF"]} +{"kind": "grid", "row": ["123abc", "456def", "", "789ghi", "", "000"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["r45a", "r45b", "r45c", "r45d", "r45e", "r45f"]} +{"kind": "grid", "row": ["alpha9", "", "beta8", "", "gamma7", ""]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["A1B2C3", "D4E5F6", "G7H8I9", "J0", "K1", "L2"]} +{"kind": "grid", "row": ["short1", "", "short3", "", "short5", ""]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["r50a", "r50b", "r50c", "r50d", "r50e", "r50f"]} +{"kind": "grid", "row": ["x1y2", "z3", "", "w4", "", "v5"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["longertext", "mid", "small", "s1", "s22", "s333"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["r55a", "r55b", "r55c", "r55d", "r55e", "r55f"]} +{"kind": "grid", "row": ["abc", "def", "ghi", "jkl", "mno", "pqr"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["1a", "2b", "3c", "4d", "5e", "6f"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["row60a", "row60b", "row60c", "row60d", "row60e", "row60f"]} +{"kind": "grid", "row": ["value1", "", "value3", "", "value5", ""]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["aa", "bb", "cc", "dd", "ee", "ff"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["r65a", "r65b", "r65c", "r65d", "r65e", "r65f"]} +{"kind": "grid", "row": ["x", "", "y", "", "z", ""]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["alpha01", "beta02", "gamma03", "delta04", "eps05", "z6"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["row70a", "row70b", "row70c", "row70d", "row70e", "row70f"]} +{"kind": "grid", "row": ["1", "", "3", "", "5", ""]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["abc1", "def2", "ghi3", "jkl4", "mno5", "pqr6"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["r75a", "r75b", "r75c", "r75d", "r75e", "r75f"]} +{"kind": "grid", "row": ["mix", "", "mix2", "", "mix3", ""]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["a", "b", "c", "d", "e", "f"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["row80a", "row80b", "row80c", "row80d", "row80e", "row80f"]} +{"kind": "grid", "row": ["123", "234", "345", "456", "567", "678"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["Aaa", "Bbb", "Ccc", "Ddd", "Eee", "Fff"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["r85a", "r85b", "r85c", "r85d", "r85e", "r85f"]} +{"kind": "grid", "row": ["x1", "", "x3", "", "x5", ""]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["abcde12345", "f1", "g2", "h3", "i4", "j5"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["row90a", "row90b", "row90c", "row90d", "row90e", "row90f"]} +{"kind": "grid", "row": ["1a2b3c", "", "4d5e6f", "", "7g8h9i", ""]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["short", "", "mid", "", "longer", ""]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["r95a", "r95b", "r95c", "r95d", "r95e", "r95f"]} +{"kind": "grid", "row": ["a1b", "", "c2d", "", "e3f", ""]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} +{"kind": "grid", "row": ["end1", "end2", "end3", "end4", "end5", "end6"]} +{"kind": "grid", "row": ["", "", "", "", "", ""]} diff --git a/tests/data/complex.tsv b/tests/data/complex.tsv new file mode 100644 index 0000000..3a7645d --- /dev/null +++ b/tests/data/complex.tsv @@ -0,0 +1,115 @@ +A1 B22 C333 D4444 E55555 F666666 +alpha1 b2 c3 d4 e5 f6 + === - next - line has no value + +x1 y22 z333 +=== - next - line has linefeed +" +""1""2h"", 34567890a" abc DEF123 " + + +" gh 9 +a "b +" c + === - next - lines has tab +" l ongtext01" "mi d2" s tt uuu vvvv + " " " " +R1C1 R1C2 R1C3 R1C4 R1C5 R1C6 + === - next - line is multibyte value +aaあい いろ2 ぼんさんが へを こいた .!... +g1 h22 i333 j4444 k55555 l6 + === - next - lines has linefeed+ tab +" " " + " "n " " o333" +pqrst uv wx1 yz22 345 + +a1b2c3 XYZ 7777 k9 +short longer12 x yz end + +row15a row15b row15c row15d row15e row15f +1 22 333 4444 55555 666666 +alpha beta gamma delta epsilon zeta + +mix1 mix3 444 six6 +abc123 def456 ghi789 +z y x + +t1 t2 t3 t4 t5 t6 +r1c1 r1c2 r1c4 r1c6 +data1 data22 data333 data4444 data55555 data6 + +A B C D E F +abc 123 XYZ +one1 two22 three3 four44 five5 six66 + +r30a r30b r30c r30d r30e r30f +longvalue1 mid short s tt uuu + +x y z end +abcde fghij klmno pqrst uvwxy z + +cell1 cell3 cell5 +111 2222 33333 444444 55 6 + +row40a row40b row40c row40d row40e row40f +a1 a2 a3 a4 a5 a6 + +mixA mixC DDD FFF +123abc 456def 789ghi 000 + +r45a r45b r45c r45d r45e r45f +alpha9 beta8 gamma7 + +A1B2C3 D4E5F6 G7H8I9 J0 K1 L2 +short1 short3 short5 + +r50a r50b r50c r50d r50e r50f +x1y2 z3 w4 v5 + +longertext mid small s1 s22 s333 + +r55a r55b r55c r55d r55e r55f +abc def ghi jkl mno pqr + +1a 2b 3c 4d 5e 6f + +row60a row60b row60c row60d row60e row60f +value1 value3 value5 + +aa bb cc dd ee ff + +r65a r65b r65c r65d r65e r65f +x y z + +alpha01 beta02 gamma03 delta04 eps05 z6 + +row70a row70b row70c row70d row70e row70f +1 3 5 + +abc1 def2 ghi3 jkl4 mno5 pqr6 + +r75a r75b r75c r75d r75e r75f +mix mix2 mix3 + +a b c d e f + +row80a row80b row80c row80d row80e row80f +123 234 345 456 567 678 + +Aaa Bbb Ccc Ddd Eee Fff + +r85a r85b r85c r85d r85e r85f +x1 x3 x5 + +abcde12345 f1 g2 h3 i4 j5 + +row90a row90b row90c row90d row90e row90f +1a2b3c 4d5e6f 7g8h9i + +short mid longer + +r95a r95b r95c r95d r95e r95f +a1b c2d e3f + +end1 end2 end3 end4 end5 end6 + diff --git a/tests/run.sh b/tests/run.sh index 4b82eca..4a24c27 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -1,5 +1,6 @@ -#!/bin/sh -set -eu +#!/usr/bin/env bash + +set -euo pipefail SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) ROOT_DIR=$(cd "$SCRIPT_DIR/.." && pwd) @@ -14,9 +15,21 @@ RED_BG='\033[41m' WHITE='\033[37m' RESET='\033[0m' +# disable color +if [ -n "${NO_COLOR:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then + GREEN="" + RED="" + RESET="" + BOLD="" + RED_BG="" + WHITE="" +fi + UPDATE=0 +FAIL_FAST=${FAIL_FAST:-0} PATTERNS="" + for arg in "$@"; do if [ "$arg" = "--update" ]; then UPDATE=1 @@ -28,17 +41,17 @@ done FAILED_FILE=$(mktemp) trap 'rm -f "$FAILED_FILE"' EXIT -find "$CASES_DIR" -type d -print0 | +TOTAL=0 + while IFS= read -r -d '' d; do - # runner must be present - if [ ! -f "$d/run.sh" ]; then + if [ ! -f "$d/run.sh" ] && [ ! -f "$d/run.vim" ]; then continue fi name=${d#"$CASES_DIR"/} - # If patterns are provided, only run cases that match at least one pattern + # --- filter --- if [ -n "$PATTERNS" ]; then matched=0 for p in $PATTERNS; do @@ -49,36 +62,55 @@ while IFS= read -r -d '' d; do [ "$matched" -eq 1 ] || continue fi + TOTAL=$((TOTAL+1)) + + if [ "$UPDATE" -eq 1 ]; then + if [ -f "$d/out-expected.txt" ]; then + continue + fi + fi + + if [ -n "${GITHUB_ACTIONS:-}" ]; then + echo "::group::test $name" + fi + printf "%-40s ... " "$name" if ( cd "$d" - rm -f diff-*.txt gen.* stdout.txt stderr.txt out-actual + rm -f diff-*.txt gen.* stdout.txt stderr.txt out-actual.txt - sh run.sh > stdout.txt 2> stderr.txt + if [ -f run.sh ]; then + sh run.sh > stdout.txt 2> stderr.txt + else + NVIM_TIRENVI_DEV=1 nvim --headless -u NONE -n -S run.vim \ + > stdout.txt 2> stderr.txt + fi if [ "$UPDATE" -eq 1 ]; then - if [ -f out-expected ]; then - echo "Refusing update: out-expected already exists" + if [ -f out-expected.txt ]; then + echo "Refusing update: out-expected.txt already exists" exit 1 fi - mv out-actual out-expected + mv out-actual.txt out-expected.txt exit 0 fi - if [ ! -f out-expected ]; then - echo "Missing out-expected" + if [ ! -f out-expected.txt ]; then + echo "Missing out-expected.txt" exit 1 fi diff_file="diff-$name.txt" diff_file=$(printf '%s' "$diff_file" | tr ' /' '__') - if diff -u out-expected out-actual > "$diff_file"; then - rm "$diff_file" + + if diff -u out-expected.txt out-actual.txt > "$diff_file"; then + rm "$diff_file" else - echo "DIFF FOUND (see $diff_file)" - exit 1 + echo "DIFF FOUND (see $diff_file)" + exit 1 fi + ); then if [ "$UPDATE" -eq 1 ]; then printf "${GREEN}UPDATED${RESET}\n" @@ -88,15 +120,24 @@ while IFS= read -r -d '' d; do else printf "${RED}FAIL${RESET}\n" echo "$name" >> "$FAILED_FILE" + + if [ "$FAIL_FAST" -eq 1 ]; then + printf "\n${BOLD}${RED}FAIL-FAST: stopping after first failure${RESET}" + exit 1 + fi fi -done + + if [ -n "${GITHUB_ACTIONS:-}" ]; then + echo "::endgroup::" + fi + +done < <(find "$CASES_DIR" -type d -print0) if [ -s "$FAILED_FILE" ]; then - echo - echo "${BOLD}${RED_BG}${WHITE} FAILED CASES ${RESET}" - sed 's/^/ - /' "$FAILED_FILE" + count=$(grep -c '^' "$FAILED_FILE") + printf "\n${BOLD}${RED_BG}${WHITE} FAILED CASES ($count) ${RESET}\n" + awk '{printf("%3d. %s\n", NR, $0)}' "$FAILED_FILE" exit 1 fi -echo -echo "${BOLD}${GREEN}ALL TESTS PASSED${RESET}" +printf "\n${BOLD}${GREEN}ALL TESTS PASSED (${TOTAL} cases)${RESET}\n" \ No newline at end of file