Compare commits

..

No commits in common. "master" and "1.0.0" have entirely different histories.

40 changed files with 1366 additions and 4260 deletions

View File

@ -1,11 +0,0 @@
disabled_rules:
- force_cast
- force_try
- variable_name
included:
- Sources
line_length: 300
file_length: 1500
cyclomatic_complexity:
warning: 15
error: 20

View File

@ -1,8 +1,12 @@
language: swift
osx_image: xcode11.3
language: objective-c
osx_image: xcode8
env:
- LC_CTYPE=en_US.UTF-8
git:
submodules: false
before_install:
- git submodule update --init --recursive
script:
- set -o pipefail && xcodebuild test -scheme CSV-macOS
after_success:
- bash <(curl -s https://codecov.io/bash)
- set -o pipefail && xcodebuild test -scheme CSV-OSX
notifications:
email: false

View File

@ -1,18 +1,17 @@
Pod::Spec.new do |spec|
spec.name = 'CSV.swift'
spec.version = '2.4.3'
spec.license = { :type => 'MIT' }
spec.homepage = 'https://github.com/yaslab/CSV.swift'
spec.authors = { 'Yasuhiro Hatta' => 'hatta.yasuhiro@gmail.com' }
spec.summary = 'CSV reading and writing library written in Swift.'
spec.source = { :git => 'https://github.com/yaslab/CSV.swift.git', :tag => spec.version }
spec.source_files = 'Sources/CSV/*.swift'
Pod::Spec.new do |s|
s.name = 'CSV.swift'
s.version = '1.0.0'
s.license = 'MIT'
s.summary = 'CSV reading library written in Swift.'
s.homepage = 'https://github.com/yaslab/CSV.swift'
s.authors = { 'Yasuhiro Hatta' => 'hatta.yasuhiro@gmail.com' }
s.source = { :git => 'https://github.com/yaslab/CSV.swift.git', :tag => s.version }
spec.ios.deployment_target = '8.0'
spec.tvos.deployment_target = '9.0'
spec.watchos.deployment_target = '2.0'
spec.osx.deployment_target = '10.9'
s.osx.deployment_target = '10.9'
s.ios.deployment_target = '8.0'
s.tvos.deployment_target = '9.0'
s.watchos.deployment_target = '2.0'
spec.module_name = 'CSV'
spec.swift_version = '5.0'
s.module_name = 'CSV'
s.source_files = 'Sources/*.swift'
end

View File

@ -7,72 +7,54 @@
objects = {
/* Begin PBXBuildFile section */
0E54021B1ED9DDF40019C3ED /* CSVWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E54021A1ED9DDF40019C3ED /* CSVWriterTests.swift */; };
0E54021C1ED9DDF40019C3ED /* CSVWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E54021A1ED9DDF40019C3ED /* CSVWriterTests.swift */; };
0E54021D1ED9DDF40019C3ED /* CSVWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E54021A1ED9DDF40019C3ED /* CSVWriterTests.swift */; };
0E0F16091D197D6000C92580 /* AnyIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F16081D197D6000C92580 /* AnyIterator.swift */; };
0E0F160A1D197D6000C92580 /* AnyIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F16081D197D6000C92580 /* AnyIterator.swift */; };
0E0F160B1D197D6000C92580 /* AnyIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F16081D197D6000C92580 /* AnyIterator.swift */; };
0E0F160C1D197D6000C92580 /* AnyIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F16081D197D6000C92580 /* AnyIterator.swift */; };
0E0F160E1D197DB800C92580 /* Endian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F160D1D197DB800C92580 /* Endian.swift */; };
0E0F160F1D197DB800C92580 /* Endian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F160D1D197DB800C92580 /* Endian.swift */; };
0E0F16101D197DB800C92580 /* Endian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F160D1D197DB800C92580 /* Endian.swift */; };
0E0F16111D197DB800C92580 /* Endian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F160D1D197DB800C92580 /* Endian.swift */; };
0E7E8C8C1D0BC7BB0057A1C1 /* CSV.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E7E8C811D0BC7BB0057A1C1 /* CSV.framework */; };
0E7E8CA11D0BC7F10057A1C1 /* CSV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9D1D0BC7F10057A1C1 /* CSV.swift */; };
0E7E8CA21D0BC7F10057A1C1 /* CSVError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9E1D0BC7F10057A1C1 /* CSVError.swift */; };
0E7E8CA31D0BC7F10057A1C1 /* CSVVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E7E8C9F1D0BC7F10057A1C1 /* CSVVersion.h */; settings = {ATTRIBUTES = (Public, ); }; };
0E7E8CA91D0BC8050057A1C1 /* CSVReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8CA61D0BC8050057A1C1 /* CSVReaderTests.swift */; };
0E7E8CAA1D0BC8050057A1C1 /* CSVTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8CA71D0BC8050057A1C1 /* CSVTests.swift */; };
0E7E8CBE1D0BC9D70057A1C1 /* CSV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9D1D0BC7F10057A1C1 /* CSV.swift */; };
0E7E8CBF1D0BC9D70057A1C1 /* CSVError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9E1D0BC7F10057A1C1 /* CSVError.swift */; };
0E7E8CC01D0BC9D70057A1C1 /* CSVVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E7E8C9F1D0BC7F10057A1C1 /* CSVVersion.h */; settings = {ATTRIBUTES = (Public, ); }; };
0E7E8CD01D0BCA2A0057A1C1 /* CSV.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E7E8CC61D0BCA2A0057A1C1 /* CSV.framework */; };
0E7E8CDD1D0BCA840057A1C1 /* CSVReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8CA61D0BC8050057A1C1 /* CSVReaderTests.swift */; };
0E7E8CDE1D0BCA840057A1C1 /* CSVTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8CA71D0BC8050057A1C1 /* CSVTests.swift */; };
0E7E8CE01D0BCA8E0057A1C1 /* CSV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9D1D0BC7F10057A1C1 /* CSV.swift */; };
0E7E8CE11D0BCA8E0057A1C1 /* CSVError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9E1D0BC7F10057A1C1 /* CSVError.swift */; };
0E7E8CE21D0BCA8E0057A1C1 /* CSVVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E7E8C9F1D0BC7F10057A1C1 /* CSVVersion.h */; settings = {ATTRIBUTES = (Public, ); }; };
0E7E8CF21D0BCD0B0057A1C1 /* CSV.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E7E8CE81D0BCD0B0057A1C1 /* CSV.framework */; };
0E7E8D001D0BCDCF0057A1C1 /* CSV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9D1D0BC7F10057A1C1 /* CSV.swift */; };
0E7E8D011D0BCDCF0057A1C1 /* CSVError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9E1D0BC7F10057A1C1 /* CSVError.swift */; };
0E7E8D021D0BCDCF0057A1C1 /* CSVVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E7E8C9F1D0BC7F10057A1C1 /* CSVVersion.h */; settings = {ATTRIBUTES = (Public, ); }; };
0E7F657B1EF6437E00E1E1A0 /* Version1Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7F657A1EF6437E00E1E1A0 /* Version1Tests.swift */; };
0E7F657C1EF6437E00E1E1A0 /* Version1Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7F657A1EF6437E00E1E1A0 /* Version1Tests.swift */; };
0E7F657D1EF6437E00E1E1A0 /* Version1Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7F657A1EF6437E00E1E1A0 /* Version1Tests.swift */; };
0E87607B219D992900C6C7FA /* BinaryReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E87607A219D992900C6C7FA /* BinaryReaderTests.swift */; };
0E87607C219D992900C6C7FA /* BinaryReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E87607A219D992900C6C7FA /* BinaryReaderTests.swift */; };
0E87607D219D992900C6C7FA /* BinaryReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E87607A219D992900C6C7FA /* BinaryReaderTests.swift */; };
0E87607F219FF43B00C6C7FA /* CSVRowDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E87607E219FF43B00C6C7FA /* CSVRowDecoder.swift */; };
0E876080219FF43B00C6C7FA /* CSVRowDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E87607E219FF43B00C6C7FA /* CSVRowDecoder.swift */; };
0E876081219FF43B00C6C7FA /* CSVRowDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E87607E219FF43B00C6C7FA /* CSVRowDecoder.swift */; };
0E876082219FF43B00C6C7FA /* CSVRowDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E87607E219FF43B00C6C7FA /* CSVRowDecoder.swift */; };
0E959C62208B611F005F8D01 /* CSVError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5B208B611F005F8D01 /* CSVError.swift */; };
0E959C63208B611F005F8D01 /* CSVError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5B208B611F005F8D01 /* CSVError.swift */; };
0E959C64208B611F005F8D01 /* CSVError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5B208B611F005F8D01 /* CSVError.swift */; };
0E959C65208B611F005F8D01 /* CSVError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5B208B611F005F8D01 /* CSVError.swift */; };
0E959C66208B611F005F8D01 /* CSVWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5C208B611F005F8D01 /* CSVWriter.swift */; };
0E959C67208B611F005F8D01 /* CSVWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5C208B611F005F8D01 /* CSVWriter.swift */; };
0E959C68208B611F005F8D01 /* CSVWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5C208B611F005F8D01 /* CSVWriter.swift */; };
0E959C69208B611F005F8D01 /* CSVWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5C208B611F005F8D01 /* CSVWriter.swift */; };
0E959C6A208B611F005F8D01 /* Legacy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5D208B611F005F8D01 /* Legacy.swift */; };
0E959C6B208B611F005F8D01 /* Legacy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5D208B611F005F8D01 /* Legacy.swift */; };
0E959C6C208B611F005F8D01 /* Legacy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5D208B611F005F8D01 /* Legacy.swift */; };
0E959C6D208B611F005F8D01 /* Legacy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5D208B611F005F8D01 /* Legacy.swift */; };
0E959C6E208B611F005F8D01 /* BinaryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5E208B611F005F8D01 /* BinaryReader.swift */; };
0E959C6F208B611F005F8D01 /* BinaryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5E208B611F005F8D01 /* BinaryReader.swift */; };
0E959C70208B611F005F8D01 /* BinaryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5E208B611F005F8D01 /* BinaryReader.swift */; };
0E959C71208B611F005F8D01 /* BinaryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5E208B611F005F8D01 /* BinaryReader.swift */; };
0E959C72208B611F005F8D01 /* UnicodeIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5F208B611F005F8D01 /* UnicodeIterator.swift */; };
0E959C73208B611F005F8D01 /* UnicodeIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5F208B611F005F8D01 /* UnicodeIterator.swift */; };
0E959C74208B611F005F8D01 /* UnicodeIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5F208B611F005F8D01 /* UnicodeIterator.swift */; };
0E959C75208B611F005F8D01 /* UnicodeIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C5F208B611F005F8D01 /* UnicodeIterator.swift */; };
0E959C76208B611F005F8D01 /* Endian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C60208B611F005F8D01 /* Endian.swift */; };
0E959C77208B611F005F8D01 /* Endian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C60208B611F005F8D01 /* Endian.swift */; };
0E959C78208B611F005F8D01 /* Endian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C60208B611F005F8D01 /* Endian.swift */; };
0E959C79208B611F005F8D01 /* Endian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C60208B611F005F8D01 /* Endian.swift */; };
0E959C7A208B611F005F8D01 /* CSVReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C61208B611F005F8D01 /* CSVReader.swift */; };
0E959C7B208B611F005F8D01 /* CSVReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C61208B611F005F8D01 /* CSVReader.swift */; };
0E959C7C208B611F005F8D01 /* CSVReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C61208B611F005F8D01 /* CSVReader.swift */; };
0E959C7D208B611F005F8D01 /* CSVReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E959C61208B611F005F8D01 /* CSVReader.swift */; };
0EDF8ED71DDB73520068056A /* CSVReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ECD1DDB73370068056A /* CSVReaderTests.swift */; };
0EDF8ED81DDB73520068056A /* LineBreakTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ECE1DDB73370068056A /* LineBreakTests.swift */; };
0EDF8ED91DDB73520068056A /* ReadmeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ECF1DDB73370068056A /* ReadmeTests.swift */; };
0EDF8EDA1DDB73520068056A /* TrimFieldsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ED01DDB73370068056A /* TrimFieldsTests.swift */; };
0EDF8EDB1DDB73520068056A /* UnicodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ED11DDB73370068056A /* UnicodeTests.swift */; };
0EDF8EDC1DDB73520068056A /* CSVReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ECD1DDB73370068056A /* CSVReaderTests.swift */; };
0EDF8EDD1DDB73520068056A /* LineBreakTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ECE1DDB73370068056A /* LineBreakTests.swift */; };
0EDF8EDE1DDB73520068056A /* ReadmeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ECF1DDB73370068056A /* ReadmeTests.swift */; };
0EDF8EDF1DDB73520068056A /* TrimFieldsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ED01DDB73370068056A /* TrimFieldsTests.swift */; };
0EDF8EE01DDB73520068056A /* UnicodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ED11DDB73370068056A /* UnicodeTests.swift */; };
0EDF8EE11DDB73530068056A /* CSVReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ECD1DDB73370068056A /* CSVReaderTests.swift */; };
0EDF8EE21DDB73530068056A /* LineBreakTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ECE1DDB73370068056A /* LineBreakTests.swift */; };
0EDF8EE31DDB73530068056A /* ReadmeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ECF1DDB73370068056A /* ReadmeTests.swift */; };
0EDF8EE41DDB73530068056A /* TrimFieldsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ED01DDB73370068056A /* TrimFieldsTests.swift */; };
0EDF8EE51DDB73530068056A /* UnicodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDF8ED11DDB73370068056A /* UnicodeTests.swift */; };
3C89219E21484154004AA78A /* CSVRowDecoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C89219D21484153004AA78A /* CSVRowDecoderTests.swift */; };
3C89219F21484154004AA78A /* CSVRowDecoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C89219D21484153004AA78A /* CSVRowDecoderTests.swift */; };
3C8921A021484154004AA78A /* CSVRowDecoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C89219D21484153004AA78A /* CSVRowDecoderTests.swift */; };
0E7E8D031D0BCDDD0057A1C1 /* CSVReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8CA61D0BC8050057A1C1 /* CSVReaderTests.swift */; };
0E7E8D041D0BCDDD0057A1C1 /* CSVTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8CA71D0BC8050057A1C1 /* CSVTests.swift */; };
0E9317D41D0DB2F200AC20A0 /* CSV+init.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9317D31D0DB2F200AC20A0 /* CSV+init.swift */; };
0E9317D51D0DB2F200AC20A0 /* CSV+init.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9317D31D0DB2F200AC20A0 /* CSV+init.swift */; };
0E9317D61D0DB2F200AC20A0 /* CSV+init.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9317D31D0DB2F200AC20A0 /* CSV+init.swift */; };
0E9317D71D0DB2F200AC20A0 /* CSV+init.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9317D31D0DB2F200AC20A0 /* CSV+init.swift */; };
0E9317D91D0DB30800AC20A0 /* CSV+subscript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9317D81D0DB30800AC20A0 /* CSV+subscript.swift */; };
0E9317DA1D0DB30800AC20A0 /* CSV+subscript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9317D81D0DB30800AC20A0 /* CSV+subscript.swift */; };
0E9317DB1D0DB30800AC20A0 /* CSV+subscript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9317D81D0DB30800AC20A0 /* CSV+subscript.swift */; };
0E9317DC1D0DB30800AC20A0 /* CSV+subscript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9317D81D0DB30800AC20A0 /* CSV+subscript.swift */; };
0E9317DE1D0DBCC500AC20A0 /* ReadmeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9317DD1D0DBCC500AC20A0 /* ReadmeTests.swift */; };
0E9317DF1D0DBCC500AC20A0 /* ReadmeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9317DD1D0DBCC500AC20A0 /* ReadmeTests.swift */; };
0E9317E01D0DBCC500AC20A0 /* ReadmeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9317DD1D0DBCC500AC20A0 /* ReadmeTests.swift */; };
0EA2AB7C1D183B45003EC967 /* BinaryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2AB7B1D183B45003EC967 /* BinaryReader.swift */; };
0EA2AB7D1D183B45003EC967 /* BinaryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2AB7B1D183B45003EC967 /* BinaryReader.swift */; };
0EA2AB7E1D183B45003EC967 /* BinaryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2AB7B1D183B45003EC967 /* BinaryReader.swift */; };
0EA2AB7F1D183B45003EC967 /* BinaryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2AB7B1D183B45003EC967 /* BinaryReader.swift */; };
0EA2AB811D183BA9003EC967 /* UnicodeIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2AB801D183BA9003EC967 /* UnicodeIterator.swift */; };
0EA2AB821D183BA9003EC967 /* UnicodeIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2AB801D183BA9003EC967 /* UnicodeIterator.swift */; };
0EA2AB831D183BA9003EC967 /* UnicodeIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2AB801D183BA9003EC967 /* UnicodeIterator.swift */; };
0EA2AB841D183BA9003EC967 /* UnicodeIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2AB801D183BA9003EC967 /* UnicodeIterator.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -81,14 +63,14 @@
containerPortal = 0E7E8C781D0BC7BB0057A1C1 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 0E7E8C801D0BC7BB0057A1C1;
remoteInfo = "CSV-iOS";
remoteInfo = CSV;
};
0E7E8CD11D0BCA2A0057A1C1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 0E7E8C781D0BC7BB0057A1C1 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 0E7E8CC51D0BCA2A0057A1C1;
remoteInfo = "CSV-macOS";
remoteInfo = "CSV-OSX";
};
0E7E8CF31D0BCD0B0057A1C1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
@ -100,33 +82,27 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
0E54021A1ED9DDF40019C3ED /* CSVWriterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSVWriterTests.swift; sourceTree = "<group>"; };
0E0F16081D197D6000C92580 /* AnyIterator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyIterator.swift; sourceTree = "<group>"; };
0E0F160D1D197DB800C92580 /* Endian.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Endian.swift; sourceTree = "<group>"; };
0E7E8C811D0BC7BB0057A1C1 /* CSV.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CSV.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0E7E8C8B1D0BC7BB0057A1C1 /* CSVTests-iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "CSVTests-iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
0E7E8C9D1D0BC7F10057A1C1 /* CSV.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSV.swift; sourceTree = "<group>"; };
0E7E8C9E1D0BC7F10057A1C1 /* CSVError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSVError.swift; sourceTree = "<group>"; };
0E7E8C9F1D0BC7F10057A1C1 /* CSVVersion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSVVersion.h; sourceTree = "<group>"; };
0E7E8CA61D0BC8050057A1C1 /* CSVReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSVReaderTests.swift; sourceTree = "<group>"; };
0E7E8CA71D0BC8050057A1C1 /* CSVTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSVTests.swift; sourceTree = "<group>"; };
0E7E8CAC1D0BC8610057A1C1 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0E7E8CAE1D0BC8690057A1C1 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0E7E8CB51D0BC98B0057A1C1 /* CSV.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CSV.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0E7E8CC61D0BCA2A0057A1C1 /* CSV.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CSV.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0E7E8CCF1D0BCA2A0057A1C1 /* CSVTests-macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "CSVTests-macOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
0E7E8CCF1D0BCA2A0057A1C1 /* CSVTests-OSX.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "CSVTests-OSX.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
0E7E8CE81D0BCD0B0057A1C1 /* CSV.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CSV.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0E7E8CF11D0BCD0B0057A1C1 /* CSVTests-tvOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "CSVTests-tvOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
0E7F657A1EF6437E00E1E1A0 /* Version1Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Version1Tests.swift; sourceTree = "<group>"; };
0E87607A219D992900C6C7FA /* BinaryReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinaryReaderTests.swift; sourceTree = "<group>"; };
0E87607E219FF43B00C6C7FA /* CSVRowDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CSVRowDecoder.swift; sourceTree = "<group>"; };
0E959C5B208B611F005F8D01 /* CSVError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSVError.swift; sourceTree = "<group>"; };
0E959C5C208B611F005F8D01 /* CSVWriter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSVWriter.swift; sourceTree = "<group>"; };
0E959C5D208B611F005F8D01 /* Legacy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Legacy.swift; sourceTree = "<group>"; };
0E959C5E208B611F005F8D01 /* BinaryReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinaryReader.swift; sourceTree = "<group>"; };
0E959C5F208B611F005F8D01 /* UnicodeIterator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnicodeIterator.swift; sourceTree = "<group>"; };
0E959C60208B611F005F8D01 /* Endian.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Endian.swift; sourceTree = "<group>"; };
0E959C61208B611F005F8D01 /* CSVReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSVReader.swift; sourceTree = "<group>"; };
0EDF8ECD1DDB73370068056A /* CSVReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSVReaderTests.swift; sourceTree = "<group>"; };
0EDF8ECE1DDB73370068056A /* LineBreakTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineBreakTests.swift; sourceTree = "<group>"; };
0EDF8ECF1DDB73370068056A /* ReadmeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadmeTests.swift; sourceTree = "<group>"; };
0EDF8ED01DDB73370068056A /* TrimFieldsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrimFieldsTests.swift; sourceTree = "<group>"; };
0EDF8ED11DDB73370068056A /* UnicodeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnicodeTests.swift; sourceTree = "<group>"; };
3C89219D21484153004AA78A /* CSVRowDecoderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CSVRowDecoderTests.swift; sourceTree = "<group>"; };
0E9317D31D0DB2F200AC20A0 /* CSV+init.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CSV+init.swift"; sourceTree = "<group>"; };
0E9317D81D0DB30800AC20A0 /* CSV+subscript.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CSV+subscript.swift"; sourceTree = "<group>"; };
0E9317DD1D0DBCC500AC20A0 /* ReadmeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadmeTests.swift; sourceTree = "<group>"; };
0EA2AB7B1D183B45003EC967 /* BinaryReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinaryReader.swift; sourceTree = "<group>"; };
0EA2AB801D183BA9003EC967 /* UnicodeIterator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnicodeIterator.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -193,7 +169,6 @@
0E7E8C821D0BC7BB0057A1C1 /* Products */,
);
sourceTree = "<group>";
usesTabs = 0;
};
0E7E8C821D0BC7BB0057A1C1 /* Products */ = {
isa = PBXGroup;
@ -202,7 +177,7 @@
0E7E8C8B1D0BC7BB0057A1C1 /* CSVTests-iOS.xctest */,
0E7E8CB51D0BC98B0057A1C1 /* CSV.framework */,
0E7E8CC61D0BCA2A0057A1C1 /* CSV.framework */,
0E7E8CCF1D0BCA2A0057A1C1 /* CSVTests-macOS.xctest */,
0E7E8CCF1D0BCA2A0057A1C1 /* CSVTests-OSX.xctest */,
0E7E8CE81D0BCD0B0057A1C1 /* CSV.framework */,
0E7E8CF11D0BCD0B0057A1C1 /* CSVTests-tvOS.xctest */,
);
@ -212,9 +187,16 @@
0E7E8C9B1D0BC7F10057A1C1 /* Sources */ = {
isa = PBXGroup;
children = (
0E959C5A208B611F005F8D01 /* CSV */,
0E0F16081D197D6000C92580 /* AnyIterator.swift */,
0EA2AB7B1D183B45003EC967 /* BinaryReader.swift */,
0E7E8C9D1D0BC7F10057A1C1 /* CSV.swift */,
0E9317D31D0DB2F200AC20A0 /* CSV+init.swift */,
0E9317D81D0DB30800AC20A0 /* CSV+subscript.swift */,
0E7E8C9E1D0BC7F10057A1C1 /* CSVError.swift */,
0E7E8C9F1D0BC7F10057A1C1 /* CSVVersion.h */,
0E0F160D1D197DB800C92580 /* Endian.swift */,
0E7E8CAC1D0BC8610057A1C1 /* Info.plist */,
0EA2AB801D183BA9003EC967 /* UnicodeIterator.swift */,
);
path = Sources;
sourceTree = "<group>";
@ -222,43 +204,22 @@
0E7E8CA41D0BC8050057A1C1 /* Tests */ = {
isa = PBXGroup;
children = (
0EA37AC81DD8C0B900F5B274 /* CSVTests */,
0E7E8CA51D0BC8050057A1C1 /* CSV */,
0E7E8CAE1D0BC8690057A1C1 /* Info.plist */,
);
path = Tests;
sourceTree = "<group>";
};
0E959C5A208B611F005F8D01 /* CSV */ = {
0E7E8CA51D0BC8050057A1C1 /* CSV */ = {
isa = PBXGroup;
children = (
0E959C5E208B611F005F8D01 /* BinaryReader.swift */,
0E959C5D208B611F005F8D01 /* Legacy.swift */,
0E959C5B208B611F005F8D01 /* CSVError.swift */,
0E959C61208B611F005F8D01 /* CSVReader.swift */,
0E87607E219FF43B00C6C7FA /* CSVRowDecoder.swift */,
0E959C5C208B611F005F8D01 /* CSVWriter.swift */,
0E959C60208B611F005F8D01 /* Endian.swift */,
0E959C5F208B611F005F8D01 /* UnicodeIterator.swift */,
0E7E8CA61D0BC8050057A1C1 /* CSVReaderTests.swift */,
0E7E8CA71D0BC8050057A1C1 /* CSVTests.swift */,
0E9317DD1D0DBCC500AC20A0 /* ReadmeTests.swift */,
);
path = CSV;
sourceTree = "<group>";
};
0EA37AC81DD8C0B900F5B274 /* CSVTests */ = {
isa = PBXGroup;
children = (
0E87607A219D992900C6C7FA /* BinaryReaderTests.swift */,
0EDF8ECD1DDB73370068056A /* CSVReaderTests.swift */,
3C89219D21484153004AA78A /* CSVRowDecoderTests.swift */,
0E54021A1ED9DDF40019C3ED /* CSVWriterTests.swift */,
0EDF8ECE1DDB73370068056A /* LineBreakTests.swift */,
0EDF8ECF1DDB73370068056A /* ReadmeTests.swift */,
0EDF8ED01DDB73370068056A /* TrimFieldsTests.swift */,
0EDF8ED11DDB73370068056A /* UnicodeTests.swift */,
0E7F657A1EF6437E00E1E1A0 /* Version1Tests.swift */,
);
path = CSVTests;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@ -329,7 +290,7 @@
0E7E8C8E1D0BC7BB0057A1C1 /* PBXTargetDependency */,
);
name = "CSVTests-iOS";
productName = "CSVTests-iOS";
productName = CSVTests;
productReference = 0E7E8C8B1D0BC7BB0057A1C1 /* CSVTests-iOS.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
@ -351,11 +312,10 @@
productReference = 0E7E8CB51D0BC98B0057A1C1 /* CSV.framework */;
productType = "com.apple.product-type.framework";
};
0E7E8CC51D0BCA2A0057A1C1 /* CSV-macOS */ = {
0E7E8CC51D0BCA2A0057A1C1 /* CSV-OSX */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0E7E8CD71D0BCA2A0057A1C1 /* Build configuration list for PBXNativeTarget "CSV-macOS" */;
buildConfigurationList = 0E7E8CD71D0BCA2A0057A1C1 /* Build configuration list for PBXNativeTarget "CSV-OSX" */;
buildPhases = (
0E47EEBF1DBBC05700EBF783 /* Run Script () */,
0E7E8CC11D0BCA2A0057A1C1 /* Sources */,
0E7E8CC21D0BCA2A0057A1C1 /* Frameworks */,
0E7E8CC31D0BCA2A0057A1C1 /* Headers */,
@ -365,14 +325,14 @@
);
dependencies = (
);
name = "CSV-macOS";
productName = "CSV-macOS";
name = "CSV-OSX";
productName = "CSV-OSX";
productReference = 0E7E8CC61D0BCA2A0057A1C1 /* CSV.framework */;
productType = "com.apple.product-type.framework";
};
0E7E8CCE1D0BCA2A0057A1C1 /* CSVTests-macOS */ = {
0E7E8CCE1D0BCA2A0057A1C1 /* CSVTests-OSX */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0E7E8CDA1D0BCA2A0057A1C1 /* Build configuration list for PBXNativeTarget "CSVTests-macOS" */;
buildConfigurationList = 0E7E8CDA1D0BCA2A0057A1C1 /* Build configuration list for PBXNativeTarget "CSVTests-OSX" */;
buildPhases = (
0E7E8CCB1D0BCA2A0057A1C1 /* Sources */,
0E7E8CCC1D0BCA2A0057A1C1 /* Frameworks */,
@ -383,9 +343,9 @@
dependencies = (
0E7E8CD21D0BCA2A0057A1C1 /* PBXTargetDependency */,
);
name = "CSVTests-macOS";
productName = "CSVTests-macOS";
productReference = 0E7E8CCF1D0BCA2A0057A1C1 /* CSVTests-macOS.xctest */;
name = "CSVTests-OSX";
productName = "CSV-OSXTests";
productReference = 0E7E8CCF1D0BCA2A0057A1C1 /* CSVTests-OSX.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
0E7E8CE71D0BCD0B0057A1C1 /* CSV-tvOS */ = {
@ -420,7 +380,7 @@
0E7E8CF41D0BCD0B0057A1C1 /* PBXTargetDependency */,
);
name = "CSVTests-tvOS";
productName = "CSVTests-tvOS";
productName = "CSV-tvOSTests";
productReference = 0E7E8CF11D0BCD0B0057A1C1 /* CSVTests-tvOS.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
@ -430,17 +390,17 @@
0E7E8C781D0BC7BB0057A1C1 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1010;
LastUpgradeCheck = 1020;
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = yaslab;
TargetAttributes = {
0E7E8C801D0BC7BB0057A1C1 = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1020;
LastSwiftMigration = 0800;
};
0E7E8C8A1D0BC7BB0057A1C1 = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1020;
LastSwiftMigration = 0800;
};
0E7E8CB41D0BC98B0057A1C1 = {
CreatedOnToolsVersion = 7.3.1;
@ -448,11 +408,11 @@
};
0E7E8CC51D0BCA2A0057A1C1 = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1020;
LastSwiftMigration = 0800;
};
0E7E8CCE1D0BCA2A0057A1C1 = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1020;
LastSwiftMigration = 0800;
};
0E7E8CE71D0BCD0B0057A1C1 = {
CreatedOnToolsVersion = 7.3.1;
@ -460,28 +420,27 @@
};
0E7E8CF01D0BCD0B0057A1C1 = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0930;
LastSwiftMigration = 0800;
};
};
};
buildConfigurationList = 0E7E8C7B1D0BC7BB0057A1C1 /* Build configuration list for PBXProject "CSV" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 0E7E8C771D0BC7BB0057A1C1;
productRefGroup = 0E7E8C821D0BC7BB0057A1C1 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
0E7E8CC51D0BCA2A0057A1C1 /* CSV-macOS */,
0E7E8CC51D0BCA2A0057A1C1 /* CSV-OSX */,
0E7E8C801D0BC7BB0057A1C1 /* CSV-iOS */,
0E7E8CE71D0BCD0B0057A1C1 /* CSV-tvOS */,
0E7E8CB41D0BC98B0057A1C1 /* CSV-watchOS */,
0E7E8CCE1D0BCA2A0057A1C1 /* CSVTests-macOS */,
0E7E8CCE1D0BCA2A0057A1C1 /* CSVTests-OSX */,
0E7E8C8A1D0BC7BB0057A1C1 /* CSVTests-iOS */,
0E7E8CF01D0BCD0B0057A1C1 /* CSVTests-tvOS */,
);
@ -540,36 +499,19 @@
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
0E47EEBF1DBBC05700EBF783 /* Run Script () */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script ()";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if which swiftlint >/dev/null; then\n swiftlint autocorrect\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
0E7E8C7C1D0BC7BB0057A1C1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0E959C63208B611F005F8D01 /* CSVError.swift in Sources */,
0E876080219FF43B00C6C7FA /* CSVRowDecoder.swift in Sources */,
0E959C6F208B611F005F8D01 /* BinaryReader.swift in Sources */,
0E959C77208B611F005F8D01 /* Endian.swift in Sources */,
0E959C67208B611F005F8D01 /* CSVWriter.swift in Sources */,
0E959C73208B611F005F8D01 /* UnicodeIterator.swift in Sources */,
0E959C6B208B611F005F8D01 /* Legacy.swift in Sources */,
0E959C7B208B611F005F8D01 /* CSVReader.swift in Sources */,
0E9317D51D0DB2F200AC20A0 /* CSV+init.swift in Sources */,
0E0F160A1D197D6000C92580 /* AnyIterator.swift in Sources */,
0EA2AB821D183BA9003EC967 /* UnicodeIterator.swift in Sources */,
0E9317DA1D0DB30800AC20A0 /* CSV+subscript.swift in Sources */,
0E7E8CA11D0BC7F10057A1C1 /* CSV.swift in Sources */,
0E0F160F1D197DB800C92580 /* Endian.swift in Sources */,
0E7E8CA21D0BC7F10057A1C1 /* CSVError.swift in Sources */,
0EA2AB7D1D183B45003EC967 /* BinaryReader.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -577,15 +519,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0EDF8EDE1DDB73520068056A /* ReadmeTests.swift in Sources */,
3C89219F21484154004AA78A /* CSVRowDecoderTests.swift in Sources */,
0EDF8EDC1DDB73520068056A /* CSVReaderTests.swift in Sources */,
0EDF8EDF1DDB73520068056A /* TrimFieldsTests.swift in Sources */,
0E7F657C1EF6437E00E1E1A0 /* Version1Tests.swift in Sources */,
0EDF8EE01DDB73520068056A /* UnicodeTests.swift in Sources */,
0E87607C219D992900C6C7FA /* BinaryReaderTests.swift in Sources */,
0EDF8EDD1DDB73520068056A /* LineBreakTests.swift in Sources */,
0E54021C1ED9DDF40019C3ED /* CSVWriterTests.swift in Sources */,
0E9317DF1D0DBCC500AC20A0 /* ReadmeTests.swift in Sources */,
0E7E8CAA1D0BC8050057A1C1 /* CSVTests.swift in Sources */,
0E7E8CA91D0BC8050057A1C1 /* CSVReaderTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -593,14 +529,14 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0E959C65208B611F005F8D01 /* CSVError.swift in Sources */,
0E876082219FF43B00C6C7FA /* CSVRowDecoder.swift in Sources */,
0E959C71208B611F005F8D01 /* BinaryReader.swift in Sources */,
0E959C79208B611F005F8D01 /* Endian.swift in Sources */,
0E959C69208B611F005F8D01 /* CSVWriter.swift in Sources */,
0E959C75208B611F005F8D01 /* UnicodeIterator.swift in Sources */,
0E959C6D208B611F005F8D01 /* Legacy.swift in Sources */,
0E959C7D208B611F005F8D01 /* CSVReader.swift in Sources */,
0E9317D71D0DB2F200AC20A0 /* CSV+init.swift in Sources */,
0E0F160C1D197D6000C92580 /* AnyIterator.swift in Sources */,
0EA2AB841D183BA9003EC967 /* UnicodeIterator.swift in Sources */,
0E9317DC1D0DB30800AC20A0 /* CSV+subscript.swift in Sources */,
0E7E8CBE1D0BC9D70057A1C1 /* CSV.swift in Sources */,
0E0F16111D197DB800C92580 /* Endian.swift in Sources */,
0E7E8CBF1D0BC9D70057A1C1 /* CSVError.swift in Sources */,
0EA2AB7F1D183B45003EC967 /* BinaryReader.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -608,14 +544,14 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0E959C62208B611F005F8D01 /* CSVError.swift in Sources */,
0E87607F219FF43B00C6C7FA /* CSVRowDecoder.swift in Sources */,
0E959C6E208B611F005F8D01 /* BinaryReader.swift in Sources */,
0E959C76208B611F005F8D01 /* Endian.swift in Sources */,
0E959C66208B611F005F8D01 /* CSVWriter.swift in Sources */,
0E959C72208B611F005F8D01 /* UnicodeIterator.swift in Sources */,
0E959C6A208B611F005F8D01 /* Legacy.swift in Sources */,
0E959C7A208B611F005F8D01 /* CSVReader.swift in Sources */,
0E9317D41D0DB2F200AC20A0 /* CSV+init.swift in Sources */,
0E0F16091D197D6000C92580 /* AnyIterator.swift in Sources */,
0EA2AB811D183BA9003EC967 /* UnicodeIterator.swift in Sources */,
0E9317D91D0DB30800AC20A0 /* CSV+subscript.swift in Sources */,
0E7E8CE01D0BCA8E0057A1C1 /* CSV.swift in Sources */,
0E0F160E1D197DB800C92580 /* Endian.swift in Sources */,
0E7E8CE11D0BCA8E0057A1C1 /* CSVError.swift in Sources */,
0EA2AB7C1D183B45003EC967 /* BinaryReader.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -623,15 +559,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0EDF8ED91DDB73520068056A /* ReadmeTests.swift in Sources */,
3C89219E21484154004AA78A /* CSVRowDecoderTests.swift in Sources */,
0EDF8ED71DDB73520068056A /* CSVReaderTests.swift in Sources */,
0EDF8EDA1DDB73520068056A /* TrimFieldsTests.swift in Sources */,
0E7F657B1EF6437E00E1E1A0 /* Version1Tests.swift in Sources */,
0EDF8EDB1DDB73520068056A /* UnicodeTests.swift in Sources */,
0E87607B219D992900C6C7FA /* BinaryReaderTests.swift in Sources */,
0EDF8ED81DDB73520068056A /* LineBreakTests.swift in Sources */,
0E54021B1ED9DDF40019C3ED /* CSVWriterTests.swift in Sources */,
0E9317DE1D0DBCC500AC20A0 /* ReadmeTests.swift in Sources */,
0E7E8CDE1D0BCA840057A1C1 /* CSVTests.swift in Sources */,
0E7E8CDD1D0BCA840057A1C1 /* CSVReaderTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -639,14 +569,14 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0E959C64208B611F005F8D01 /* CSVError.swift in Sources */,
0E876081219FF43B00C6C7FA /* CSVRowDecoder.swift in Sources */,
0E959C70208B611F005F8D01 /* BinaryReader.swift in Sources */,
0E959C78208B611F005F8D01 /* Endian.swift in Sources */,
0E959C68208B611F005F8D01 /* CSVWriter.swift in Sources */,
0E959C74208B611F005F8D01 /* UnicodeIterator.swift in Sources */,
0E959C6C208B611F005F8D01 /* Legacy.swift in Sources */,
0E959C7C208B611F005F8D01 /* CSVReader.swift in Sources */,
0E9317D61D0DB2F200AC20A0 /* CSV+init.swift in Sources */,
0E0F160B1D197D6000C92580 /* AnyIterator.swift in Sources */,
0EA2AB831D183BA9003EC967 /* UnicodeIterator.swift in Sources */,
0E9317DB1D0DB30800AC20A0 /* CSV+subscript.swift in Sources */,
0E7E8D001D0BCDCF0057A1C1 /* CSV.swift in Sources */,
0E0F16101D197DB800C92580 /* Endian.swift in Sources */,
0E7E8D011D0BCDCF0057A1C1 /* CSVError.swift in Sources */,
0EA2AB7E1D183B45003EC967 /* BinaryReader.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -654,15 +584,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0EDF8EE31DDB73530068056A /* ReadmeTests.swift in Sources */,
3C8921A021484154004AA78A /* CSVRowDecoderTests.swift in Sources */,
0EDF8EE11DDB73530068056A /* CSVReaderTests.swift in Sources */,
0EDF8EE41DDB73530068056A /* TrimFieldsTests.swift in Sources */,
0E7F657D1EF6437E00E1E1A0 /* Version1Tests.swift in Sources */,
0EDF8EE51DDB73530068056A /* UnicodeTests.swift in Sources */,
0E87607D219D992900C6C7FA /* BinaryReaderTests.swift in Sources */,
0EDF8EE21DDB73530068056A /* LineBreakTests.swift in Sources */,
0E54021D1ED9DDF40019C3ED /* CSVWriterTests.swift in Sources */,
0E9317E01D0DBCC500AC20A0 /* ReadmeTests.swift in Sources */,
0E7E8D041D0BCDDD0057A1C1 /* CSVTests.swift in Sources */,
0E7E8D031D0BCDDD0057A1C1 /* CSVReaderTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -676,7 +600,7 @@
};
0E7E8CD21D0BCA2A0057A1C1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 0E7E8CC51D0BCA2A0057A1C1 /* CSV-macOS */;
target = 0E7E8CC51D0BCA2A0057A1C1 /* CSV-OSX */;
targetProxy = 0E7E8CD11D0BCA2A0057A1C1 /* PBXContainerItemProxy */;
};
0E7E8CF41D0BCD0B0057A1C1 /* PBXTargetDependency */ = {
@ -691,29 +615,18 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@ -742,7 +655,6 @@
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
@ -753,29 +665,18 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@ -796,7 +697,6 @@
MACOSX_DEPLOYMENT_TARGET = 10.9;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
@ -807,7 +707,6 @@
0E7E8C961D0BC7BB0057A1C1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@ -816,17 +715,16 @@
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 2.4.3;
PRODUCT_BUNDLE_IDENTIFIER = net.yaslab.CSV;
PRODUCT_NAME = CSV;
SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
};
name = Debug;
};
0E7E8C971D0BC7BB0057A1C1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@ -835,34 +733,34 @@
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 2.4.3;
PRODUCT_BUNDLE_IDENTIFIER = net.yaslab.CSV;
PRODUCT_NAME = CSV;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
};
name = Release;
};
0E7E8C991D0BC7BB0057A1C1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
INFOPLIST_FILE = Tests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-iOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
};
name = Debug;
};
0E7E8C9A1D0BC7BB0057A1C1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
INFOPLIST_FILE = Tests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-iOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
};
name = Release;
};
@ -870,7 +768,6 @@
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@ -878,11 +775,11 @@
INFOPLIST_FILE = Sources/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 2.4.3;
PRODUCT_BUNDLE_IDENTIFIER = net.yaslab.CSV;
PRODUCT_NAME = CSV;
SDKROOT = watchos;
SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 2.0;
};
@ -892,7 +789,6 @@
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@ -900,12 +796,12 @@
INFOPLIST_FILE = Sources/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 2.4.3;
PRODUCT_BUNDLE_IDENTIFIER = net.yaslab.CSV;
PRODUCT_NAME = CSV;
SDKROOT = watchos;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 2.0;
};
@ -925,11 +821,11 @@
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.9;
MARKETING_VERSION = 2.4.3;
PRODUCT_BUNDLE_IDENTIFIER = net.yaslab.CSV;
PRODUCT_NAME = CSV;
SDKROOT = macosx;
SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
};
name = Debug;
};
@ -947,50 +843,49 @@
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.9;
MARKETING_VERSION = 2.4.3;
PRODUCT_BUNDLE_IDENTIFIER = net.yaslab.CSV;
PRODUCT_NAME = CSV;
SDKROOT = macosx;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
};
name = Release;
};
0E7E8CDB1D0BCA2A0057A1C1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Tests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.11;
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-macOS";
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-OSX";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SWIFT_VERSION = 3.0;
};
name = Debug;
};
0E7E8CDC1D0BCA2A0057A1C1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Tests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.11;
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-macOS";
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-OSX";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
};
name = Release;
};
0E7E8CFA1D0BCD0B0057A1C1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@ -998,11 +893,11 @@
INFOPLIST_FILE = Sources/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 2.4.3;
PRODUCT_BUNDLE_IDENTIFIER = net.yaslab.CSV;
PRODUCT_NAME = CSV;
SDKROOT = appletvos;
SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.0;
};
@ -1011,7 +906,6 @@
0E7E8CFB1D0BCD0B0057A1C1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@ -1019,12 +913,12 @@
INFOPLIST_FILE = Sources/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 2.4.3;
PRODUCT_BUNDLE_IDENTIFIER = net.yaslab.CSV;
PRODUCT_NAME = CSV;
SDKROOT = appletvos;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.0;
};
@ -1033,12 +927,12 @@
0E7E8CFD1D0BCD0B0057A1C1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
INFOPLIST_FILE = Tests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-tvOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
SWIFT_VERSION = 3.0;
TVOS_DEPLOYMENT_TARGET = 9.2;
};
name = Debug;
@ -1046,13 +940,13 @@
0E7E8CFE1D0BCD0B0057A1C1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
INFOPLIST_FILE = Tests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-tvOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
TVOS_DEPLOYMENT_TARGET = 9.2;
};
name = Release;
@ -1096,7 +990,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0E7E8CD71D0BCA2A0057A1C1 /* Build configuration list for PBXNativeTarget "CSV-macOS" */ = {
0E7E8CD71D0BCA2A0057A1C1 /* Build configuration list for PBXNativeTarget "CSV-OSX" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0E7E8CD81D0BCA2A0057A1C1 /* Debug */,
@ -1105,7 +999,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0E7E8CDA1D0BCA2A0057A1C1 /* Build configuration list for PBXNativeTarget "CSVTests-macOS" */ = {
0E7E8CDA1D0BCA2A0057A1C1 /* Build configuration list for PBXNativeTarget "CSVTests-OSX" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0E7E8CDB1D0BCA2A0057A1C1 /* Debug */,

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -16,7 +16,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "0E7E8CC51D0BCA2A0057A1C1"
BuildableName = "CSV.framework"
BlueprintName = "CSV-macOS"
BlueprintName = "CSV-OSX"
ReferencedContainer = "container:CSV.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
codeCoverageEnabled = "YES"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
@ -34,8 +33,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0E7E8CCE1D0BCA2A0057A1C1"
BuildableName = "CSVTests-macOS.xctest"
BlueprintName = "CSVTests-macOS"
BuildableName = "CSVTests-OSX.xctest"
BlueprintName = "CSVTests-OSX"
ReferencedContainer = "container:CSV.xcodeproj">
</BuildableReference>
</TestableReference>
@ -45,7 +44,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "0E7E8CC51D0BCA2A0057A1C1"
BuildableName = "CSV.framework"
BlueprintName = "CSV-macOS"
BlueprintName = "CSV-OSX"
ReferencedContainer = "container:CSV.xcodeproj">
</BuildableReference>
</MacroExpansion>
@ -67,7 +66,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "0E7E8CC51D0BCA2A0057A1C1"
BuildableName = "CSV.framework"
BlueprintName = "CSV-macOS"
BlueprintName = "CSV-OSX"
ReferencedContainer = "container:CSV.xcodeproj">
</BuildableReference>
</MacroExpansion>
@ -85,7 +84,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "0E7E8CC51D0BCA2A0057A1C1"
BuildableName = "CSV.framework"
BlueprintName = "CSV-macOS"
BlueprintName = "CSV-OSX"
ReferencedContainer = "container:CSV.xcodeproj">
</BuildableReference>
</MacroExpansion>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
codeCoverageEnabled = "YES"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -1,15 +1,7 @@
// swift-tools-version:5.0
import PackageDescription
let package = Package(
name: "CSV.swift",
products: [
.library(name: "CSV", targets: ["CSV"])
],
targets: [
.target(name: "CSV"),
.testTarget(name: "CSVTests", dependencies: ["CSV"])
],
swiftLanguageVersions: [.v5]
name: "CSV",
targets: [],
dependencies: []
)

151
README.md
View File

@ -1,38 +1,30 @@
# CSV.swift
[![Build Status](https://travis-ci.org/yaslab/CSV.swift.svg?branch=master)](https://travis-ci.org/yaslab/CSV.swift)
[![codecov](https://codecov.io/gh/yaslab/CSV.swift/branch/master/graph/badge.svg)](https://codecov.io/gh/yaslab/CSV.swift)
[![Open Source Helpers](https://www.codetriage.com/yaslab/csv.swift/badges/users.svg)](https://www.codetriage.com/yaslab/csv.swift)
CSV reading and writing library written in Swift.
CSV reading library written in Swift.
## Usage for reading CSV
## Usage
### From string
### From CSV string
```swift
import CSV
let csvString = "1,foo\n2,bar"
let csv = try! CSVReader(string: csvString)
while let row = csv.next() {
for row in try! CSV(string: "1,foo\n2,bar") {
print("\(row)")
// => ["1", "foo"]
// => ["2", "bar"]
}
// => ["1", "foo"]
// => ["2", "bar"]
```
### From file
NOTE: The default character encoding is `UTF8`.
### From file path
```swift
import Foundation
import CSV
let stream = InputStream(fileAtPath: "/path/to/file.csv")!
let csv = try! CSVReader(stream: stream)
while let row = csv.next() {
let stream = NSInputStream(fileAtPath: "/path/to/file.csv")!
for row in try! CSV(stream: stream) {
print("\(row)")
}
```
@ -40,30 +32,26 @@ while let row = csv.next() {
### Getting the header row
```swift
import CSV
let csvString = "id,name\n1,foo\n2,bar"
let csv = try! CSVReader(string: csvString,
hasHeaderRow: true) // It must be true.
let csv = try! CSV(
string: "id,name\n1,foo\n2,bar",
hasHeaderRow: true) // default: false
let headerRow = csv.headerRow!
print("\(headerRow)") // => ["id", "name"]
while let row = csv.next() {
for row in csv {
print("\(row)")
// => ["1", "foo"]
// => ["2", "bar"]
}
// => ["1", "foo"]
// => ["2", "bar"]
```
### Get the field value using subscript
```swift
import CSV
let csvString = "id,name\n1,foo"
let csv = try! CSVReader(string: csvString,
hasHeaderRow: true) // It must be true.
let csv = try! CSV(
string: "id,name\n1,foo",
hasHeaderRow: true) // It must be true.
while csv.next() != nil {
print("\(csv["id"]!)") // => "1"
@ -76,92 +64,10 @@ while csv.next() != nil {
If you use a file path, you can provide the character encoding to initializer.
```swift
import Foundation
import CSV
let stream = InputStream(fileAtPath: "/path/to/file.csv")!
let csv = try! CSVReader(stream: stream,
codecType: UTF16.self,
endian: .big)
```
### Reading a row into a Decodable object
If you have a destination object that conforms to the `Decodable` protocol, you can serialize a row with a new instances of the object.
```swift
struct DecodableExample: Decodable {
let intKey: Int
let stringKey: String
let optionalStringKey: String?
}
let csv = """
intKey,stringKey,optionalStringKey
1234,abcd,
"""
var records = [DecodableExample]()
do {
let reader = try CSVReader(string: csv, hasHeaderRow: true)
let decoder = CSVRowDecoder()
while reader.next() != nil {
let row = try decoder.decode(DecodableExample.self, from: reader)
records.append(row)
}
} catch {
// Invalid row format
}
```
## Usage for writing CSV
### Write to memory and get a CSV String
NOTE: The default character encoding is `UTF8`.
```swift
import Foundation
import CSV
let csv = try! CSVWriter(stream: .toMemory())
// Write a row
try! csv.write(row: ["id", "name"])
// Write fields separately
csv.beginNewRow()
try! csv.write(field: "1")
try! csv.write(field: "foo")
csv.beginNewRow()
try! csv.write(field: "2")
try! csv.write(field: "bar")
csv.stream.close()
// Get a String
let csvData = csv.stream.property(forKey: .dataWrittenToMemoryStreamKey) as! Data
let csvString = String(data: csvData, encoding: .utf8)!
print(csvString)
// => "id,name\n1,foo\n2,bar"
```
### Write to file
NOTE: The default character encoding is `UTF8`.
```swift
import Foundation
import CSV
let stream = OutputStream(toFileAtPath: "/path/to/file.csv", append: false)!
let csv = try! CSVWriter(stream: stream)
try! csv.write(row: ["id", "name"])
try! csv.write(row: ["1", "foo"])
try! csv.write(row: ["1", "bar"])
csv.stream.close()
let csv = try! CSV(
stream: NSInputStream(fileAtPath: "/path/to/file.csv")!,
codecType: UTF16.self,
endian: .Big)
```
## Installation
@ -169,19 +75,26 @@ csv.stream.close()
### CocoaPods
```ruby
pod 'CSV.swift', '~> 2.4.3'
pod 'CSV.swift', '~> 1.0'
```
### Carthage
```
github "yaslab/CSV.swift" ~> 2.4.3
github "yaslab/CSV.swift" ~> 1.0
```
### Swift Package Manager
```swift
.package(url: "https://github.com/yaslab/CSV.swift.git", .upToNextMinor(from: "2.4.3"))
import PackageDescription
let package = Package(
name: "PackageName",
dependencies: [
.Package(url: "https://github.com/yaslab/CSV.swift", majorVersion: 1, minor: 0)
]
)
```
## Reference specification

22
Sources/AnyIterator.swift Normal file
View File

@ -0,0 +1,22 @@
//
// AnyIterator.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/21.
// Copyright © 2016 yaslab. All rights reserved.
//
internal struct AnyIterator<T>: IteratorProtocol {
private var _base_next: (() -> T?)
internal init<U: IteratorProtocol>(base: U) where U.Element == T {
var base = base
_base_next = { base.next() }
}
internal mutating func next() -> T? {
return _base_next()
}
}

249
Sources/BinaryReader.swift Executable file
View File

@ -0,0 +1,249 @@
//
// BinaryReader.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/20.
// Copyright © 2016 yaslab. All rights reserved.
//
import Foundation
internal let utf8BOM: [UInt8] = [0xef, 0xbb, 0xbf]
internal let utf16BigEndianBOM: [UInt8] = [0xfe, 0xff]
internal let utf16LittleEndianBOM: [UInt8] = [0xff, 0xfe]
internal let utf32BigEndianBOM: [UInt8] = [0x00, 0x00, 0xfe, 0xff]
internal let utf32LittleEndianBOM: [UInt8] = [0xff, 0xfe, 0x00, 0x00]
private func readBOM(buffer: UnsafePointer<UInt8>, length: Int) -> (Endian, Int)? {
if length >= 4 {
if memcmp(buffer, utf32BigEndianBOM, 4) == 0 {
return (.big, 4)
}
if memcmp(buffer, utf32LittleEndianBOM, 4) == 0 {
return (.little, 4)
}
}
if length >= 3 {
if memcmp(buffer, utf8BOM, 3) == 0 {
return (.unknown, 3)
}
}
if length >= 2 {
if memcmp(buffer, utf16BigEndianBOM, 2) == 0 {
return (.big, 2)
}
if memcmp(buffer, utf16LittleEndianBOM, 2) == 0 {
return (.little, 2)
}
}
return nil
}
internal class BinaryReader {
private let stream: InputStream
private let endian: Endian
private let closeOnDeinit: Bool
private var buffer = [UInt8](repeating: 0, count: 4)
private var tempBuffer = [UInt8](repeating: 0, count: 4)
private let tempBufferSize = 4
private var tempBufferOffset = 0
internal init(stream: InputStream, endian: Endian = .unknown, closeOnDeinit: Bool = true) throws {
var endian = endian
if stream.streamStatus == .notOpen {
stream.open()
}
if stream.streamStatus != .open {
throw CSVError.cannotOpenFile
}
let readCount = stream.read(&tempBuffer, maxLength: tempBufferSize)
if let (e, l) = readBOM(buffer: &tempBuffer, length: readCount) {
if endian != .unknown && endian != e {
throw CSVError.stringEndianMismatch
}
endian = e
tempBufferOffset = l
}
self.stream = stream
self.endian = endian
self.closeOnDeinit = closeOnDeinit
}
deinit {
if closeOnDeinit && stream.streamStatus != .closed {
stream.close()
}
}
internal var hasBytesAvailable: Bool {
return stream.hasBytesAvailable
}
private func readStream(_ buffer: UnsafeMutablePointer<UInt8>, maxLength: Int) throws -> Int {
if stream.streamStatus != .open {
throw CSVError.cannotReadFile
}
var i = 0
while tempBufferOffset < tempBufferSize {
buffer[i] = tempBuffer[tempBufferOffset]
i += 1
tempBufferOffset += 1
if i >= maxLength {
return i
}
}
return stream.read(buffer + i, maxLength: maxLength - i)
}
internal func readUInt8() throws -> UInt8 {
let bufferSize = 1
let length = try readStream(&buffer, maxLength: bufferSize)
if length < 0 {
throw CSVError.streamErrorHasOccurred(error: stream.streamError!)
}
if length != bufferSize {
throw CSVError.cannotReadFile
}
return buffer[0]
}
internal func readUInt16() throws -> UInt16 {
let bufferSize = 2
let length = try readStream(&buffer, maxLength: bufferSize)
if length < 0 {
throw CSVError.streamErrorHasOccurred(error: stream.streamError!)
}
if length != bufferSize {
throw CSVError.stringEncodingMismatch
}
return try UnsafePointer(buffer).withMemoryRebound(to: UInt16.self, capacity: 1) {
switch endian {
case .big:
return CFSwapInt16BigToHost($0[0])
case .little:
return CFSwapInt16LittleToHost($0[0])
default:
throw CSVError.stringEndianMismatch
}
}
}
internal func readUInt32() throws -> UInt32 {
let bufferSize = 4
let length = try readStream(&buffer, maxLength: bufferSize)
if length < 0 {
throw CSVError.streamErrorHasOccurred(error: stream.streamError!)
}
if length != 4 {
throw CSVError.stringEncodingMismatch
}
return try UnsafePointer(buffer).withMemoryRebound(to: UInt32.self, capacity: 1) {
switch endian {
case .big:
return CFSwapInt32BigToHost($0[0])
case .little:
return CFSwapInt32LittleToHost($0[0])
default:
throw CSVError.stringEndianMismatch
}
}
}
}
extension BinaryReader {
internal struct UInt8Iterator: Sequence, IteratorProtocol {
private let reader: BinaryReader
fileprivate init(reader: BinaryReader) {
self.reader = reader
}
internal mutating func next() -> UInt8? {
if !reader.hasBytesAvailable {
return nil
}
do {
return try reader.readUInt8()
}
catch /*let error*/ {
return nil
}
}
}
internal func makeUInt8Iterator() -> UInt8Iterator {
return UInt8Iterator(reader: self)
}
}
extension BinaryReader {
internal struct UInt16Iterator: Sequence, IteratorProtocol {
private let reader: BinaryReader
fileprivate init(reader: BinaryReader) {
self.reader = reader
}
internal mutating func next() -> UInt16? {
if !reader.hasBytesAvailable {
return nil
}
do {
return try reader.readUInt16()
}
catch /*let error*/ {
return nil
}
}
}
internal func makeUInt16Iterator() -> UInt16Iterator {
return UInt16Iterator(reader: self)
}
}
extension BinaryReader {
internal struct UInt32Iterator: Sequence, IteratorProtocol {
private let reader: BinaryReader
fileprivate init(reader: BinaryReader) {
self.reader = reader
}
internal mutating func next() -> UInt32? {
if !reader.hasBytesAvailable {
return nil
}
do {
return try reader.readUInt32()
}
catch /*let error*/ {
return nil
}
}
}
internal func makeUInt32Iterator() -> UInt32Iterator {
return UInt32Iterator(reader: self)
}
}

36
Sources/CSV+init.swift Executable file
View File

@ -0,0 +1,36 @@
//
// CSV+init.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/13.
// Copyright © 2016 yaslab. All rights reserved.
//
import Foundation
extension CSV {
public init(
stream: InputStream,
hasHeaderRow: Bool = defaultHasHeaderRow,
delimiter: UnicodeScalar = defaultDelimiter)
throws
{
try self.init(stream: stream, codecType: UTF8.self, hasHeaderRow: hasHeaderRow, delimiter: delimiter)
}
}
extension CSV {
public init(
string: String,
hasHeaderRow: Bool = defaultHasHeaderRow,
delimiter: UnicodeScalar = defaultDelimiter)
throws
{
let iterator = string.unicodeScalars.makeIterator()
try self.init(iterator: iterator, hasHeaderRow: hasHeaderRow, delimiter: delimiter)
}
}

26
Sources/CSV+subscript.swift Executable file
View File

@ -0,0 +1,26 @@
//
// CSV+subscript.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/13.
// Copyright © 2016 yaslab. All rights reserved.
//
extension CSV {
public subscript(key: String) -> String? {
get {
guard let headerRow = headerRow, let currentRow = currentRow else {
return nil
}
guard let index = headerRow.index(of: key) else {
return nil
}
if index >= currentRow.count {
return nil
}
return currentRow[index]
}
}
}

245
Sources/CSV.swift Executable file
View File

@ -0,0 +1,245 @@
//
// CSV.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/11.
// Copyright © 2016 yaslab. All rights reserved.
//
import Foundation
private let LF = UnicodeScalar("\n")!
private let CR = UnicodeScalar("\r")!
private let DQUOTE = UnicodeScalar("\"")!
internal let defaultHasHeaderRow = false
internal let defaultDelimiter = UnicodeScalar(",")!
public struct CSV: IteratorProtocol, Sequence {
private var iterator: AnyIterator<UnicodeScalar>
private let delimiter: UnicodeScalar
private var back: UnicodeScalar? = nil
internal var currentRow: [String]? = nil
/// CSV header row. To set a value for this property, you set `true` to `hasHeaerRow` in initializer.
public var headerRow: [String]? { return _headerRow }
private var _headerRow: [String]? = nil
internal init<T: IteratorProtocol>(
iterator: T,
hasHeaderRow: Bool,
delimiter: UnicodeScalar)
throws where T.Element == UnicodeScalar
{
self.iterator = AnyIterator(base: iterator)
self.delimiter = delimiter
if hasHeaderRow {
guard let headerRow = next() else {
throw CSVError.cannotReadHeaderRow
}
_headerRow = headerRow
}
}
/// Create an instance with `InputStream`.
///
/// - parameter stream: An `InputStream` object. If the stream is not open, initializer opens automatically.
/// - parameter codecType: A `UnicodeCodec` type for `stream`.
/// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`.
/// - parameter delimiter: Default: `","`.
public init<T: UnicodeCodec>(
stream: InputStream,
codecType: T.Type,
hasHeaderRow: Bool = defaultHasHeaderRow,
delimiter: UnicodeScalar = defaultDelimiter)
throws
where T.CodeUnit == UInt8
{
let reader = try BinaryReader(stream: stream, endian: .unknown, closeOnDeinit: true)
let iterator = UnicodeIterator(input: reader.makeUInt8Iterator(), inputEncodingType: codecType)
try self.init(iterator: iterator, hasHeaderRow: hasHeaderRow, delimiter: delimiter)
}
/// Create an instance with `InputStream`.
///
/// - parameter stream: An `InputStream` object. If the stream is not open, initializer opens automatically.
/// - parameter codecType: A `UnicodeCodec` type for `stream`.
/// - parameter endian: Endian to use when reading a stream. Default: `.big`.
/// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`.
/// - parameter delimiter: Default: `","`.
public init<T: UnicodeCodec>(
stream: InputStream,
codecType: T.Type,
endian: Endian = .big,
hasHeaderRow: Bool = defaultHasHeaderRow,
delimiter: UnicodeScalar = defaultDelimiter)
throws
where T.CodeUnit == UInt16
{
let reader = try BinaryReader(stream: stream, endian: endian, closeOnDeinit: true)
let iterator = UnicodeIterator(input: reader.makeUInt16Iterator(), inputEncodingType: codecType)
try self.init(iterator: iterator, hasHeaderRow: hasHeaderRow, delimiter: delimiter)
}
/// Create an instance with `InputStream`.
///
/// - parameter stream: An `InputStream` object. If the stream is not open, initializer opens automatically.
/// - parameter codecType: A `UnicodeCodec` type for `stream`.
/// - parameter endian: Endian to use when reading a stream. Default: `.big`.
/// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`.
/// - parameter delimiter: Default: `","`.
public init<T: UnicodeCodec>(
stream: InputStream,
codecType: T.Type,
endian: Endian = .big,
hasHeaderRow: Bool = defaultHasHeaderRow,
delimiter: UnicodeScalar = defaultDelimiter)
throws
where T.CodeUnit == UInt32
{
let reader = try BinaryReader(stream: stream, endian: endian, closeOnDeinit: true)
let iterator = UnicodeIterator(input: reader.makeUInt32Iterator(), inputEncodingType: codecType)
try self.init(iterator: iterator, hasHeaderRow: hasHeaderRow, delimiter: delimiter)
}
// MARK: IteratorProtocol
/// Advances and returns the next element of the underlying sequence, or
/// `nil` if no next element exists.
///
/// Repeatedly calling this method returns, in order, all the elements of the
/// underlying sequence. After the sequence has run out of elements, the
/// `next()` method returns `nil`.
///
/// You must not call this method if it has previously returned `nil` or if
/// any other copy of this iterator has been advanced with a call to its
/// `next()` method.
///
/// The following example shows how an iterator can be used explicitly to
/// emulate a `for`-`in` loop. First, retrieve a sequence's iterator, and
/// then call the iterator's `next()` method until it returns `nil`.
///
/// let numbers = [2, 3, 5, 7]
/// var numbersIterator = numbers.makeIterator()
///
/// while let num = numbersIterator.next() {
/// print(num)
/// }
/// // Prints "2"
/// // Prints "3"
/// // Prints "5"
/// // Prints "7"
///
/// - Returns: The next element in the underlying sequence if a next element
/// exists; otherwise, `nil`.
public mutating func next() -> [String]? {
return readRow()
}
internal mutating func moveNext() -> UnicodeScalar? {
if back != nil {
defer { back = nil }
return back
}
return iterator.next()
}
internal mutating func readRow() -> [String]? {
currentRow = nil
var next = moveNext()
if next == nil {
return nil
}
var row = [String]()
var field: String
var end: Bool
while true {
if next == nil {
(field, end) = ("", true)
}
else if next == DQUOTE {
(field, end) = readField(quoted: true)
}
else {
back = next
(field, end) = readField(quoted: false)
}
row.append(field)
if end {
break
}
next = moveNext()
}
currentRow = row
return row
}
internal mutating func readField(quoted: Bool) -> (String, Bool) {
var field = ""
var next = moveNext()
while let c = next {
if quoted {
if c == DQUOTE {
let cNext = moveNext()
if cNext == nil || cNext == CR || cNext == LF {
if cNext == CR {
let cNextNext = moveNext()
if cNextNext != LF {
back = cNextNext
}
}
// END ROW
return (field, true)
}
else if cNext == delimiter {
// END FIELD
return (field, false)
}
else if cNext == DQUOTE {
// ESC
field.append(String(DQUOTE))
}
else {
// ERROR??
field.append(String(c))
}
}
else {
field.append(String(c))
}
}
else {
if c == CR || c == LF {
if c == CR {
let cNext = moveNext()
if cNext != LF {
back = cNext
}
}
// END ROW
return (field, true)
}
else if c == delimiter {
// END FIELD
return (field, false)
}
else {
field.append(String(c))
}
}
next = moveNext()
}
return (field, true)
}
}

View File

@ -1,295 +0,0 @@
//
// BinaryReader.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/20.
// Copyright © 2016 yaslab. All rights reserved.
//
import Foundation
enum UnicodeBOM {
// UTF-8
static let utf8: [UInt8] = [0xef, 0xbb, 0xbf]
// UTF-16 BE
static let utf16BE: [UInt8] = [0xfe, 0xff]
// UTF-16 LE
static let utf16LE: [UInt8] = [0xff, 0xfe]
// UTF-32 BE
static let utf32BE: [UInt8] = [0x00, 0x00, 0xfe, 0xff]
// UTF-32 LE
static let utf32LE: [UInt8] = [0xff, 0xfe, 0x00, 0x00]
}
extension UnicodeBOM {
fileprivate static func readBOM(buffer: UnsafePointer<UInt8>, count: Int) -> (Endian, Int)? {
if count >= 4 {
// UTF-32 BE
if compare(buffer: buffer, bom: UnicodeBOM.utf32BE) {
return (.big, UnicodeBOM.utf32BE.count)
}
// UTF-32 LE
if compare(buffer: buffer, bom: UnicodeBOM.utf32LE) {
return (.little, UnicodeBOM.utf32LE.count)
}
}
if count >= 3 {
// UTF-8
if compare(buffer: buffer, bom: UnicodeBOM.utf8) {
return (.unknown, UnicodeBOM.utf8.count)
}
}
if count >= 2 {
// UTF-16 BE
if compare(buffer: buffer, bom: UnicodeBOM.utf16BE) {
return (.big, UnicodeBOM.utf16BE.count)
}
// UTF-16 LE
if compare(buffer: buffer, bom: UnicodeBOM.utf16LE) {
return (.little, UnicodeBOM.utf16LE.count)
}
}
return nil
}
private static func compare(buffer: UnsafePointer<UInt8>, bom: [UInt8]) -> Bool {
for i in 0 ..< bom.count {
guard buffer[i] == bom[i] else {
return false
}
}
return true
}
}
internal class BinaryReader {
private let stream: InputStream
private let endian: Endian
private let closeOnDeinit: Bool
private let _buffer: UnsafeMutablePointer<UInt8>
private let _capacity: Int
private var _count: Int = 0
private var _position: Int = 0
internal init(
stream: InputStream,
endian: Endian,
closeOnDeinit: Bool,
bufferSize: Int = Int(UInt16.max)) throws {
var endian = endian
if stream.streamStatus == .notOpen {
stream.open()
}
if stream.streamStatus != .open {
throw CSVError.cannotOpenFile
}
_buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
_capacity = bufferSize
_count = stream.read(_buffer, maxLength: _capacity)
if _count < 0 {
throw CSVError.cannotReadFile
}
var position = 0
if let (e, l) = UnicodeBOM.readBOM(buffer: _buffer, count: _count) {
if endian != .unknown && endian != e {
throw CSVError.stringEndianMismatch
}
endian = e
position = l
}
_position = position
self.stream = stream
self.endian = endian
self.closeOnDeinit = closeOnDeinit
}
deinit {
if closeOnDeinit && stream.streamStatus != .closed {
stream.close()
}
_buffer.deallocate()
}
internal var hasBytesAvailable: Bool {
if _count - _position > 0 {
return true
}
return stream.hasBytesAvailable
}
@inline(__always)
private func readStream(_ buffer: UnsafeMutablePointer<UInt8>, maxLength: Int) throws -> Int {
var count = 0
for i in 0 ..< maxLength {
if _position >= _count {
let result = stream.read(_buffer, maxLength: _capacity)
if result < 0 {
if let error = stream.streamError {
throw CSVError.streamErrorHasOccurred(error: error)
} else {
throw CSVError.cannotReadFile
}
}
_count = result
_position = 0
if result == 0 {
break
}
}
buffer[i] = _buffer[_position]
_position += 1
count += 1
}
return count
}
internal func readUInt8() throws -> UInt8 {
let bufferSize = 1
var buffer: UInt8 = 0
if try readStream(&buffer, maxLength: bufferSize) != bufferSize {
throw CSVError.cannotReadFile
}
return buffer
}
internal func readUInt16() throws -> UInt16 {
let bufferSize = 2
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
defer { buffer.deallocate() }
if try readStream(buffer, maxLength: bufferSize) != bufferSize {
throw CSVError.stringEncodingMismatch
}
return try buffer.withMemoryRebound(to: UInt16.self, capacity: 1) {
switch endian {
case .big:
return UInt16(bigEndian: $0.pointee)
case .little:
return UInt16(littleEndian: $0.pointee)
default:
throw CSVError.stringEndianMismatch
}
}
}
internal func readUInt32() throws -> UInt32 {
let bufferSize = 4
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
defer { buffer.deallocate() }
if try readStream(buffer, maxLength: bufferSize) != bufferSize {
throw CSVError.stringEncodingMismatch
}
return try buffer.withMemoryRebound(to: UInt32.self, capacity: 1) {
switch endian {
case .big:
return UInt32(bigEndian: $0.pointee)
case .little:
return UInt32(littleEndian: $0.pointee)
default:
throw CSVError.stringEndianMismatch
}
}
}
}
extension BinaryReader {
internal class UInt8Iterator: Sequence, IteratorProtocol {
private let reader: BinaryReader
internal var errorHandler: ((Error) -> Void)?
fileprivate init(reader: BinaryReader) {
self.reader = reader
}
internal func next() -> UInt8? {
if !reader.hasBytesAvailable {
return nil
}
do {
return try reader.readUInt8()
} catch {
errorHandler?(error)
return nil
}
}
}
internal func makeUInt8Iterator() -> UInt8Iterator {
return UInt8Iterator(reader: self)
}
}
extension BinaryReader {
internal class UInt16Iterator: Sequence, IteratorProtocol {
private let reader: BinaryReader
internal var errorHandler: ((Error) -> Void)?
fileprivate init(reader: BinaryReader) {
self.reader = reader
}
internal func next() -> UInt16? {
if !reader.hasBytesAvailable {
return nil
}
do {
return try reader.readUInt16()
} catch {
errorHandler?(error)
return nil
}
}
}
internal func makeUInt16Iterator() -> UInt16Iterator {
return UInt16Iterator(reader: self)
}
}
extension BinaryReader {
internal class UInt32Iterator: Sequence, IteratorProtocol {
private let reader: BinaryReader
internal var errorHandler: ((Error) -> Void)?
fileprivate init(reader: BinaryReader) {
self.reader = reader
}
internal func next() -> UInt32? {
if !reader.hasBytesAvailable {
return nil
}
do {
return try reader.readUInt32()
} catch {
errorHandler?(error)
return nil
}
}
}
internal func makeUInt32Iterator() -> UInt32Iterator {
return UInt32Iterator(reader: self)
}
}

View File

@ -1,391 +0,0 @@
//
// CSVReader.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/11.
// Copyright © 2016 yaslab. All rights reserved.
//
import Foundation
internal let LF: UnicodeScalar = "\n"
internal let CR: UnicodeScalar = "\r"
internal let DQUOTE: UnicodeScalar = "\""
internal let DQUOTE_STR: String = "\""
internal let DQUOTE2_STR: String = "\"\""
/// No overview available.
public class CSVReader {
/// No overview available.
public struct Configuration {
/// `true` if the CSV has a header row, otherwise `false`. Default: `false`.
public var hasHeaderRow: Bool
/// No overview available.
public var trimFields: Bool
/// Default: `","`.
public var delimiter: UnicodeScalar
/// No overview available.
public var whitespaces: CharacterSet
/// No overview available.
internal init(
hasHeaderRow: Bool,
trimFields: Bool,
delimiter: UnicodeScalar,
whitespaces: CharacterSet) {
self.hasHeaderRow = hasHeaderRow
self.trimFields = trimFields
self.delimiter = delimiter
var whitespaces = whitespaces
_ = whitespaces.remove(delimiter)
self.whitespaces = whitespaces
}
}
fileprivate var iterator: AnyIterator<UnicodeScalar>
public let configuration: Configuration
public fileprivate (set) var error: Error?
fileprivate var back: UnicodeScalar?
/// CSV header row. To set a value for this property,
/// you set `true` to `headerRow` in initializer.
public private (set) var headerRow: [String]?
public fileprivate (set) var currentRow: [String]?
internal init<T: IteratorProtocol>(
iterator: T,
configuration: Configuration
) throws where T.Element == UnicodeScalar {
self.iterator = AnyIterator(iterator)
self.configuration = configuration
if configuration.hasHeaderRow {
guard let headerRow = readRow() else {
throw CSVError.cannotReadHeaderRow
}
self.headerRow = headerRow
self.currentRow = nil
}
}
}
extension CSVReader {
public static let defaultHasHeaderRow: Bool = false
public static let defaultTrimFields: Bool = false
public static let defaultDelimiter: UnicodeScalar = ","
public static let defaultWhitespaces: CharacterSet = .whitespaces
/// Create an instance with `InputStream`.
///
/// - parameter stream: An `InputStream` object. If the stream is not open,
/// initializer opens automatically.
/// - parameter codecType: A `UnicodeCodec` type for `stream`.
/// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`.
/// - parameter delimiter: Default: `","`.
public convenience init<T: UnicodeCodec>(
stream: InputStream,
codecType: T.Type,
hasHeaderRow: Bool = defaultHasHeaderRow,
trimFields: Bool = defaultTrimFields,
delimiter: UnicodeScalar = defaultDelimiter,
whitespaces: CharacterSet = defaultWhitespaces
) throws where T.CodeUnit == UInt8 {
let reader = try BinaryReader(stream: stream, endian: .unknown, closeOnDeinit: true)
let input = reader.makeUInt8Iterator()
let iterator = UnicodeIterator(input: input, inputEncodingType: codecType)
let config = Configuration(hasHeaderRow: hasHeaderRow,
trimFields: trimFields,
delimiter: delimiter,
whitespaces: whitespaces)
try self.init(iterator: iterator, configuration: config)
input.errorHandler = { [unowned self] in self.errorHandler(error: $0) }
iterator.errorHandler = { [unowned self] in self.errorHandler(error: $0) }
}
/// Create an instance with `InputStream`.
///
/// - parameter stream: An `InputStream` object. If the stream is not open,
/// initializer opens automatically.
/// - parameter codecType: A `UnicodeCodec` type for `stream`.
/// - parameter endian: Endian to use when reading a stream. Default: `.big`.
/// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`.
/// - parameter delimiter: Default: `","`.
public convenience init<T: UnicodeCodec>(
stream: InputStream,
codecType: T.Type,
endian: Endian = .big,
hasHeaderRow: Bool = defaultHasHeaderRow,
trimFields: Bool = defaultTrimFields,
delimiter: UnicodeScalar = defaultDelimiter,
whitespaces: CharacterSet = defaultWhitespaces
) throws where T.CodeUnit == UInt16 {
let reader = try BinaryReader(stream: stream, endian: endian, closeOnDeinit: true)
let input = reader.makeUInt16Iterator()
let iterator = UnicodeIterator(input: input, inputEncodingType: codecType)
let config = Configuration(hasHeaderRow: hasHeaderRow,
trimFields: trimFields,
delimiter: delimiter,
whitespaces: whitespaces)
try self.init(iterator: iterator, configuration: config)
input.errorHandler = { [unowned self] in self.errorHandler(error: $0) }
iterator.errorHandler = { [unowned self] in self.errorHandler(error: $0) }
}
/// Create an instance with `InputStream`.
///
/// - parameter stream: An `InputStream` object. If the stream is not open,
/// initializer opens automatically.
/// - parameter codecType: A `UnicodeCodec` type for `stream`.
/// - parameter endian: Endian to use when reading a stream. Default: `.big`.
/// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`.
/// - parameter delimiter: Default: `","`.
public convenience init<T: UnicodeCodec>(
stream: InputStream,
codecType: T.Type,
endian: Endian = .big,
hasHeaderRow: Bool = defaultHasHeaderRow,
trimFields: Bool = defaultTrimFields,
delimiter: UnicodeScalar = defaultDelimiter,
whitespaces: CharacterSet = defaultWhitespaces
) throws where T.CodeUnit == UInt32 {
let reader = try BinaryReader(stream: stream, endian: endian, closeOnDeinit: true)
let input = reader.makeUInt32Iterator()
let iterator = UnicodeIterator(input: input, inputEncodingType: codecType)
let config = Configuration(hasHeaderRow: hasHeaderRow,
trimFields: trimFields,
delimiter: delimiter,
whitespaces: whitespaces)
try self.init(iterator: iterator, configuration: config)
input.errorHandler = { [unowned self] in self.errorHandler(error: $0) }
iterator.errorHandler = { [unowned self] in self.errorHandler(error: $0) }
}
/// Create an instance with `InputStream`.
///
/// - parameter stream: An `InputStream` object. If the stream is not open,
/// initializer opens automatically.
/// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`.
/// - parameter delimiter: Default: `","`.
public convenience init(
stream: InputStream,
hasHeaderRow: Bool = defaultHasHeaderRow,
trimFields: Bool = defaultTrimFields,
delimiter: UnicodeScalar = defaultDelimiter,
whitespaces: CharacterSet = defaultWhitespaces
) throws {
try self.init(
stream: stream,
codecType: UTF8.self,
hasHeaderRow: hasHeaderRow,
trimFields: trimFields,
delimiter: delimiter,
whitespaces: whitespaces)
}
/// Create an instance with CSV string.
///
/// - parameter string: An CSV string.
/// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`.
/// - parameter delimiter: Default: `","`.
public convenience init(
string: String,
hasHeaderRow: Bool = defaultHasHeaderRow,
trimFields: Bool = defaultTrimFields,
delimiter: UnicodeScalar = defaultDelimiter,
whitespaces: CharacterSet = defaultWhitespaces
) throws {
let iterator = string.unicodeScalars.makeIterator()
let config = Configuration(hasHeaderRow: hasHeaderRow,
trimFields: trimFields,
delimiter: delimiter,
whitespaces: whitespaces)
try self.init(iterator: iterator, configuration: config)
}
private func errorHandler(error: Error) {
//configuration.fileInputErrorHandler?(error, currentRowIndex, currentFieldIndex)
self.error = error
}
}
// MARK: - Parse CSV
extension CSVReader {
fileprivate func readRow() -> [String]? {
var c = moveNext()
if c == nil {
currentRow = nil
return nil
}
var row = [String]()
var field: String
var end: Bool
while true {
if configuration.trimFields {
// Trim the leading spaces
while c != nil && configuration.whitespaces.contains(c!) {
c = moveNext()
}
}
if c == nil {
(field, end) = ("", true)
} else if c == DQUOTE {
(field, end) = readField(quoted: true)
} else {
back = c
(field, end) = readField(quoted: false)
if configuration.trimFields {
// Trim the trailing spaces
field = field.trimmingCharacters(in: configuration.whitespaces)
}
}
row.append(field)
if end {
break
}
c = moveNext()
}
currentRow = row
return row
}
private func readField(quoted: Bool) -> (String, Bool) {
var fieldBuffer = String.UnicodeScalarView()
while let c = moveNext() {
if quoted {
if c == DQUOTE {
var cNext = moveNext()
if configuration.trimFields {
// Trim the trailing spaces
while cNext != nil && configuration.whitespaces.contains(cNext!) {
cNext = moveNext()
}
}
if cNext == nil || cNext == CR || cNext == LF {
if cNext == CR {
let cNextNext = moveNext()
if cNextNext != LF {
back = cNextNext
}
}
// END ROW
return (String(fieldBuffer), true)
} else if cNext == configuration.delimiter {
// END FIELD
return (String(fieldBuffer), false)
} else if cNext == DQUOTE {
// ESC
fieldBuffer.append(DQUOTE)
} else {
// ERROR?
fieldBuffer.append(c)
}
} else {
fieldBuffer.append(c)
}
} else {
if c == CR || c == LF {
if c == CR {
let cNext = moveNext()
if cNext != LF {
back = cNext
}
}
// END ROW
return (String(fieldBuffer), true)
} else if c == configuration.delimiter {
// END FIELD
return (String(fieldBuffer), false)
} else {
fieldBuffer.append(c)
}
}
}
// END FILE
return (String(fieldBuffer), true)
}
private func moveNext() -> UnicodeScalar? {
if back != nil {
defer {
back = nil
}
return back
}
return iterator.next()
}
}
//extension CSVReader {
//
// public func enumerateRows(_ block: ((CSVReader, inout Bool) throws -> Void)) throws {
// var stop = false
// while next() != nil {
// try block(self, &stop)
// if stop {
// break
// }
// }
// if let error = error {
// throw error
// }
// }
//
//}
extension CSVReader: IteratorProtocol {
@discardableResult
public func next() -> [String]? {
return readRow()
}
}
extension CSVReader {
public subscript(key: String) -> String? {
guard let header = headerRow else {
fatalError("CSVReader.headerRow must not be nil")
}
guard let index = header.firstIndex(of: key) else {
return nil
}
guard let row = currentRow else {
fatalError("CSVReader.currentRow must not be nil")
}
guard index < row.count else {
return ""
}
return row[index]
}
}

View File

@ -1,749 +0,0 @@
//
// CSVRowDecoder.swift
// CSV
//
// Created by Yasuhiro Hatta on 2018/11/17.
// Copyright © 2018 yaslab. All rights reserved.
//
import Foundation
/// `CSVRowDecoder` facilitates the decoding of CSV row into semantic `Decodable` types.
open class CSVRowDecoder {
/// The strategy to use for decoding `Bool` values.
public enum BoolDecodingStrategy {
/// Decode the `Bool` using default initializer.
case `default`
/// Decode the `Bool` as a custom value decoded by the given closure.
case custom((_ value: String) throws -> Bool)
}
/// The strategy to use for decoding `Date` values.
public enum DateDecodingStrategy {
/// Defer to `Date` for decoding. This is the default strategy.
case deferredToDate
/// Decode the `Date` as a UNIX timestamp from a JSON number.
case secondsSince1970
/// Decode the `Date` as UNIX millisecond timestamp from a JSON number.
case millisecondsSince1970
/// Decode the `Date` as an ISO-8601-formatted string (in RFC 3339 format).
@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
case iso8601
/// Decode the `Date` as a string parsed by the given formatter.
case formatted(DateFormatter)
/// Decode the `Date` as a custom value decoded by the given closure.
case custom((_ value: String) throws -> Date)
}
/// The strategy to use for decoding `Data` values.
public enum DataDecodingStrategy {
// TODO: Implement unkeyed decoding container.
// /// Defer to `Data` for decoding.
// case deferredToData
/// Decode the `Data` from a Base64-encoded string. This is the default strategy.
case base64
/// Decode the `Data` as a custom value decoded by the given closure.
case custom((_ value: String) throws -> Data)
}
/// The strategy to use for decoding `nil` values.
public enum NilDecodingStrategy {
case empty
case custom((_ value: String) -> Bool)
}
/// The strategy to use in decoding bools. Defaults to `.default`.
open var boolDecodingStrategy: BoolDecodingStrategy = .default
/// The strategy to use in decoding dates. Defaults to `.deferredToDate`.
open var dateDecodingStrategy: DateDecodingStrategy = .deferredToDate
/// The strategy to use in decoding binary data. Defaults to `.base64`.
open var dataDecodingStrategy: DataDecodingStrategy = .base64
/// The strategy to use in decoding nil data. Defaults to `.empty`.
open var nilDecodingStrategy: NilDecodingStrategy = .empty
/// Contextual user-provided information for use during decoding.
open var userInfo: [CodingUserInfoKey: Any] = [:]
/// Options set on the top-level encoder to pass down the decoding hierarchy.
fileprivate struct _Options {
let boolDecodingStrategy: BoolDecodingStrategy
let dateDecodingStrategy: DateDecodingStrategy
let dataDecodingStrategy: DataDecodingStrategy
let nilDecodingStrategy: NilDecodingStrategy
let userInfo: [CodingUserInfoKey: Any]
}
/// The options set on the top-level decoder.
fileprivate var options: _Options {
return _Options(boolDecodingStrategy: boolDecodingStrategy,
dateDecodingStrategy: dateDecodingStrategy,
dataDecodingStrategy: dataDecodingStrategy,
nilDecodingStrategy: nilDecodingStrategy,
userInfo: userInfo)
}
/// Initializes `self` with default strategies.
public init() {}
/// Decodes a top-level value of the given type from the given CSV row representation.
open func decode<T: Decodable>(_ type: T.Type, from reader: CSVReader) throws -> T {
let decoder = _CSVRowDecoder(referencing: reader, options: self.options)
return try type.init(from: decoder)
}
}
fileprivate final class _CSVRowDecoder: Decoder {
fileprivate let reader: CSVReader
fileprivate let options: CSVRowDecoder._Options
public var codingPath: [CodingKey] = []
public var userInfo: [CodingUserInfoKey: Any] {
return self.options.userInfo
}
fileprivate init(referencing reader: CSVReader, options: CSVRowDecoder._Options) {
self.reader = reader
self.options = options
}
public func container<Key: CodingKey>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> {
let container = CSVKeyedDecodingContainer<Key>(referencing: self)
return KeyedDecodingContainer(container)
}
public func unkeyedContainer() throws -> UnkeyedDecodingContainer {
throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self,
DecodingError.Context(codingPath: self.codingPath,
debugDescription: "Cannot get unkeyed decoding container -- found null value instead."))
}
public func singleValueContainer() throws -> SingleValueDecodingContainer {
return self
}
}
fileprivate final class CSVKeyedDecodingContainer<K: CodingKey>: KeyedDecodingContainerProtocol {
typealias Key = K
private let decoder: _CSVRowDecoder
public var codingPath: [CodingKey] {
return self.decoder.codingPath
}
public var allKeys: [Key] {
guard let headerRow = self.decoder.reader.headerRow else { return [] }
return headerRow.compactMap { Key(stringValue: $0) }
}
fileprivate init(referencing decoder: _CSVRowDecoder) {
self.decoder = decoder
}
private func value(for key: Key) throws -> String {
guard self.contains(key) else {
throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\")."))
}
if let index = key.intValue {
return self.decoder.reader.currentRow![index]
} else {
return self.decoder.reader[key.stringValue]!
}
}
private func _valueNotFound(_ type: Any.Type) -> DecodingError {
let description = "Expected \(type) value but found null instead."
return .valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: description))
}
public func contains(_ key: Key) -> Bool {
guard let row = self.decoder.reader.currentRow else { return false }
if let index = key.intValue {
return index < row.count
} else {
guard let headerRow = self.decoder.reader.headerRow else {
return false
}
return headerRow.contains(key.stringValue)
}
}
public func decodeNil(forKey key: Key) throws -> Bool {
switch decoder.options.nilDecodingStrategy {
case .empty:
return try self.value(for: key).isEmpty
case .custom(let customClosure):
return customClosure(try self.value(for: key))
}
}
public func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool {
let value = try self.value(for: key)
self.decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
guard let result = try self.decoder.unbox(value, as: Bool.self) else {
throw _valueNotFound(type)
}
return result
}
public func decode(_ type: String.Type, forKey key: Key) throws -> String {
let value = try self.value(for: key)
self.decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
guard let result = try self.decoder.unbox(value, as: String.self) else {
throw _valueNotFound(type)
}
return result
}
public func decode(_ type: Double.Type, forKey key: Key) throws -> Double {
let value = try self.value(for: key)
self.decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
guard let result = try self.decoder.unbox(value, as: Double.self) else {
throw _valueNotFound(type)
}
return result
}
public func decode(_ type: Float.Type, forKey key: Key) throws -> Float {
let value = try self.value(for: key)
self.decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
guard let result = try self.decoder.unbox(value, as: Float.self) else {
throw _valueNotFound(type)
}
return result
}
public func decode(_ type: Int.Type, forKey key: Key) throws -> Int {
let value = try self.value(for: key)
self.decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
guard let result = try self.decoder.unbox(value, as: Int.self) else {
throw _valueNotFound(type)
}
return result
}
public func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 {
let value = try self.value(for: key)
self.decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
guard let result = try self.decoder.unbox(value, as: Int8.self) else {
throw _valueNotFound(type)
}
return result
}
public func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 {
let value = try self.value(for: key)
self.decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
guard let result = try self.decoder.unbox(value, as: Int16.self) else {
throw _valueNotFound(type)
}
return result
}
public func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 {
let value = try self.value(for: key)
self.decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
guard let result = try self.decoder.unbox(value, as: Int32.self) else {
throw _valueNotFound(type)
}
return result
}
public func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 {
let value = try self.value(for: key)
self.decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
guard let result = try self.decoder.unbox(value, as: Int64.self) else {
throw _valueNotFound(type)
}
return result
}
public func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt {
let value = try self.value(for: key)
self.decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
guard let result = try self.decoder.unbox(value, as: UInt.self) else {
throw _valueNotFound(type)
}
return result
}
public func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 {
let value = try self.value(for: key)
self.decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
guard let result = try self.decoder.unbox(value, as: UInt8.self) else {
throw _valueNotFound(type)
}
return result
}
public func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 {
let value = try self.value(for: key)
self.decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
guard let result = try self.decoder.unbox(value, as: UInt16.self) else {
throw _valueNotFound(type)
}
return result
}
public func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 {
let value = try self.value(for: key)
self.decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
guard let result = try self.decoder.unbox(value, as: UInt32.self) else {
throw _valueNotFound(type)
}
return result
}
public func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 {
let value = try self.value(for: key)
self.decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
guard let result = try self.decoder.unbox(value, as: UInt64.self) else {
throw _valueNotFound(type)
}
return result
}
public func decode<T: Decodable>(_ type: T.Type, forKey key: Key) throws -> T {
let value = try self.value(for: key)
self.decoder.codingPath.append(key)
defer { self.decoder.codingPath.removeLast() }
guard let result = try self.decoder.unbox(value, as: type) else {
throw _valueNotFound(type)
}
return result
}
public func nestedContainer<NestedKey: CodingKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> {
// Not supported
throw DecodingError.dataCorrupted(
DecodingError.Context(codingPath: self.codingPath,
debugDescription: "nestedContainer(...) CSV does not support nested values")
)
}
public func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
// Not supported
throw DecodingError.dataCorrupted(
DecodingError.Context(codingPath: self.codingPath,
debugDescription: "nestedUnkeyedContainer(...) CSV does not support nested values")
)
}
public func superDecoder() throws -> Decoder {
// Not supported
throw DecodingError.dataCorrupted(
DecodingError.Context(codingPath: self.codingPath,
debugDescription: "CSV does not support nested values")
)
}
public func superDecoder(forKey key: Key) throws -> Decoder {
// Not supported
throw DecodingError.dataCorrupted(
DecodingError.Context(codingPath: self.codingPath,
debugDescription: "CSV does not support nested values")
)
}
}
extension _CSVRowDecoder: SingleValueDecodingContainer {
private var value: String {
let key = self.codingPath.last!
if let index = key.intValue {
return self.reader.currentRow![index]
} else {
return self.reader[key.stringValue]!
}
}
private func expectNonNull(_ type: Any.Type) throws {
guard !self.decodeNil() else {
let description = "Expected \(type) but found null value instead."
throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: description))
}
}
public func decodeNil() -> Bool {
switch options.nilDecodingStrategy {
case .empty:
return self.value.isEmpty
case .custom(let customClosure):
return customClosure(self.value)
}
}
public func decode(_ type: Bool.Type) throws -> Bool {
try self.expectNonNull(type)
return try self.unbox(self.value, as: Bool.self)!
}
public func decode(_ type: Int.Type) throws -> Int {
try self.expectNonNull(type)
return try self.unbox(self.value, as: Int.self)!
}
public func decode(_ type: Int8.Type) throws -> Int8 {
try self.expectNonNull(type)
return try self.unbox(self.value, as: Int8.self)!
}
public func decode(_ type: Int16.Type) throws -> Int16 {
try self.expectNonNull(type)
return try self.unbox(self.value, as: Int16.self)!
}
public func decode(_ type: Int32.Type) throws -> Int32 {
try self.expectNonNull(type)
return try self.unbox(self.value, as: Int32.self)!
}
public func decode(_ type: Int64.Type) throws -> Int64 {
try self.expectNonNull(type)
return try self.unbox(self.value, as: Int64.self)!
}
public func decode(_ type: UInt.Type) throws -> UInt {
try self.expectNonNull(type)
return try self.unbox(self.value, as: UInt.self)!
}
public func decode(_ type: UInt8.Type) throws -> UInt8 {
try self.expectNonNull(type)
return try self.unbox(self.value, as: UInt8.self)!
}
public func decode(_ type: UInt16.Type) throws -> UInt16 {
try self.expectNonNull(type)
return try self.unbox(self.value, as: UInt16.self)!
}
public func decode(_ type: UInt32.Type) throws -> UInt32 {
try self.expectNonNull(type)
return try self.unbox(self.value, as: UInt32.self)!
}
public func decode(_ type: UInt64.Type) throws -> UInt64 {
try self.expectNonNull(type)
return try self.unbox(self.value, as: UInt64.self)!
}
public func decode(_ type: Float.Type) throws -> Float {
try self.expectNonNull(type)
return try self.unbox(self.value, as: Float.self)!
}
public func decode(_ type: Double.Type) throws -> Double {
try self.expectNonNull(type)
return try self.unbox(self.value, as: Double.self)!
}
public func decode(_ type: String.Type) throws -> String {
try self.expectNonNull(type)
return try self.unbox(self.value, as: String.self)!
}
public func decode<T: Decodable>(_ type: T.Type) throws -> T {
try self.expectNonNull(type)
return try self.unbox(self.value, as: type)!
}
}
extension _CSVRowDecoder {
private func _typeMismatch(at path: [CodingKey], expectation: Any.Type, reality: String) -> DecodingError {
let description = "Expected to decode \(expectation) but found \(reality) instead."
return .typeMismatch(expectation, DecodingError.Context(codingPath: path, debugDescription: description))
}
fileprivate func unbox(_ value: String, as type: Bool.Type) throws -> Bool? {
if value.isEmpty { return nil }
switch self.options.boolDecodingStrategy {
case .default:
guard let bool = Bool(value) else {
throw self._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
return bool
case .custom(let closure):
return try closure(value)
}
}
fileprivate func unbox(_ value: String, as type: Int.Type) throws -> Int? {
if value.isEmpty { return nil }
guard let int = Int(value, radix: 10) else {
throw self._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
return int
}
fileprivate func unbox(_ value: String, as type: Int8.Type) throws -> Int8? {
if value.isEmpty { return nil }
guard let int8 = Int8(value, radix: 10) else {
throw self._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
return int8
}
fileprivate func unbox(_ value: String, as type: Int16.Type) throws -> Int16? {
if value.isEmpty { return nil }
guard let int16 = Int16(value, radix: 10) else {
throw self._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
return int16
}
fileprivate func unbox(_ value: String, as type: Int32.Type) throws -> Int32? {
if value.isEmpty { return nil }
guard let int32 = Int32(value, radix: 10) else {
throw self._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
return int32
}
fileprivate func unbox(_ value: String, as type: Int64.Type) throws -> Int64? {
if value.isEmpty { return nil }
guard let int64 = Int64(value, radix: 10) else {
throw self._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
return int64
}
fileprivate func unbox(_ value: String, as type: UInt.Type) throws -> UInt? {
if value.isEmpty { return nil }
guard let uint = UInt(value, radix: 10) else {
throw self._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
return uint
}
fileprivate func unbox(_ value: String, as type: UInt8.Type) throws -> UInt8? {
if value.isEmpty { return nil }
guard let uint8 = UInt8(value, radix: 10) else {
throw self._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
return uint8
}
fileprivate func unbox(_ value: String, as type: UInt16.Type) throws -> UInt16? {
if value.isEmpty { return nil }
guard let uint16 = UInt16(value, radix: 10) else {
throw self._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
return uint16
}
fileprivate func unbox(_ value: String, as type: UInt32.Type) throws -> UInt32? {
if value.isEmpty { return nil }
guard let uint32 = UInt32(value, radix: 10) else {
throw self._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
return uint32
}
fileprivate func unbox(_ value: String, as type: UInt64.Type) throws -> UInt64? {
if value.isEmpty { return nil }
guard let uint64 = UInt64(value, radix: 10) else {
throw self._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
return uint64
}
fileprivate func unbox(_ value: String, as type: Float.Type) throws -> Float? {
if value.isEmpty { return nil }
guard let float = Float(value) else {
throw self._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
return float
}
fileprivate func unbox(_ value: String, as type: Double.Type) throws -> Double? {
if value.isEmpty { return nil }
guard let double = Double(value) else {
throw self._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
return double
}
fileprivate func unbox(_ value: String, as type: String.Type) throws -> String? {
if value.isEmpty { return nil }
return value
}
private func unbox(_ value: String, as type: Date.Type) throws -> Date? {
if value.isEmpty { return nil }
switch self.options.dateDecodingStrategy {
case .deferredToDate:
return try Date(from: self)
case .secondsSince1970:
let double = try self.unbox(value, as: Double.self)!
return Date(timeIntervalSince1970: double)
case .millisecondsSince1970:
let double = try self.unbox(value, as: Double.self)!
return Date(timeIntervalSince1970: double / 1000.0)
case .iso8601:
if #available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) {
guard let date = _iso8601Formatter.date(from: value) else {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Expected date string to be ISO8601-formatted."))
}
return date
} else {
fatalError("ISO8601DateFormatter is unavailable on this platform.")
}
case .formatted(let formatter):
guard let date = formatter.date(from: value) else {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Date string does not match format expected by formatter."))
}
return date
case .custom(let closure):
return try closure(value)
}
}
private func unbox(_ value: String, as type: Data.Type) throws -> Data? {
if value.isEmpty { return nil }
switch self.options.dataDecodingStrategy {
// TODO: Implement unkeyed decoding container.
// case .deferredToData:
// return try Data(from: self)
case .base64:
guard let data = Data(base64Encoded: value) else {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Encountered Data is not valid Base64."))
}
return data
case .custom(let closure):
return try closure(value)
}
}
fileprivate func unbox<T: Decodable>(_ value: String, as type: T.Type) throws -> T? {
if value.isEmpty { return nil }
if type == Date.self {
guard let date = try self.unbox(value, as: Date.self) else { return nil }
return (date as! T)
} else if type == Data.self {
guard let data = try self.unbox(value, as: Data.self) else { return nil }
return (data as! T)
} else if type == URL.self {
guard let url = URL(string: value) else {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath,
debugDescription: "Invalid URL string."))
}
return (url as! T)
} else if type == Decimal.self {
guard let decimal = Decimal(string: value) else {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath,
debugDescription: "Invalid Decimal string."))
}
return (decimal as! T)
} else {
return try type.init(from: self)
}
}
}
//===----------------------------------------------------------------------===//
// Shared ISO8601 Date Formatter
//===----------------------------------------------------------------------===//
// NOTE: This value is implicitly lazy and _must_ be lazy.
// We're compiled against the latest SDK (w/ ISO8601DateFormatter), but linked against whichever Foundation the user has.
// ISO8601DateFormatter might not exist, so we better not hit this code path on an older OS.
@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
fileprivate var _iso8601Formatter: ISO8601DateFormatter = {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = .withInternetDateTime
return formatter
}()

View File

@ -1,211 +0,0 @@
//
// CSVWriter.swift
// CSV
//
// Created by Yasuhiro Hatta on 2017/05/28.
// Copyright © 2017 yaslab. All rights reserved.
//
import Foundation
public class CSVWriter {
public struct Configuration {
public var delimiter: String
public var newline: String
internal init(delimiter: String, newline: Newline) {
self.delimiter = delimiter
switch newline {
case .lf: self.newline = String(LF)
case .crlf: self.newline = String(CR) + String(LF)
}
}
}
public enum Newline {
/// "\n"
case lf
/// "\r\n"
case crlf
}
public let stream: OutputStream
public let configuration: Configuration
fileprivate let writeScalar: ((UnicodeScalar) throws -> Void)
fileprivate var isFirstRow: Bool = true
fileprivate var isFirstField: Bool = true
fileprivate init(
stream: OutputStream,
configuration: Configuration,
writeScalar: @escaping ((UnicodeScalar) throws -> Void)) throws {
self.stream = stream
self.configuration = configuration
self.writeScalar = writeScalar
if stream.streamStatus == .notOpen {
stream.open()
}
if stream.streamStatus != .open {
throw CSVError.cannotOpenFile
}
}
deinit {
if stream.streamStatus == .open {
stream.close()
}
}
}
extension CSVWriter {
public static let defaultDelimiter: UnicodeScalar = ","
public convenience init(
stream: OutputStream,
delimiter: String = String(defaultDelimiter),
newline: Newline = .lf
) throws {
try self.init(stream: stream, codecType: UTF8.self, delimiter: delimiter, newline: newline)
}
public convenience init<T: UnicodeCodec>(
stream: OutputStream,
codecType: T.Type,
delimiter: String = String(defaultDelimiter),
newline: Newline = .lf
) throws where T.CodeUnit == UInt8 {
let config = Configuration(delimiter: delimiter, newline: newline)
try self.init(stream: stream, configuration: config) { (scalar: UnicodeScalar) throws in
var error: CSVError?
codecType.encode(scalar) { (code: UInt8) in
var code = code
let count = stream.write(&code, maxLength: 1)
if count != 1 {
error = CSVError.cannotWriteStream
}
}
if let error = error {
throw error
}
}
}
public convenience init<T: UnicodeCodec>(
stream: OutputStream,
codecType: T.Type,
endian: Endian = .big,
delimiter: String = String(defaultDelimiter),
newline: Newline = .lf
) throws where T.CodeUnit == UInt16 {
let config = Configuration(delimiter: delimiter, newline: newline)
try self.init(stream: stream, configuration: config) { (scalar: UnicodeScalar) throws in
var error: CSVError?
codecType.encode(scalar) { (code: UInt16) in
var code = (endian == .big) ? code.bigEndian : code.littleEndian
withUnsafeBytes(of: &code) { (buffer) -> Void in
let count = stream.write(buffer.baseAddress!.assumingMemoryBound(to: UInt8.self),
maxLength: buffer.count)
if count != buffer.count {
error = CSVError.cannotWriteStream
}
}
}
if let error = error {
throw error
}
}
}
public convenience init<T: UnicodeCodec>(
stream: OutputStream,
codecType: T.Type,
endian: Endian = .big,
delimiter: String = String(defaultDelimiter),
newline: Newline = .lf
) throws where T.CodeUnit == UInt32 {
let config = Configuration(delimiter: delimiter, newline: newline)
try self.init(stream: stream, configuration: config) { (scalar: UnicodeScalar) throws in
var error: CSVError?
codecType.encode(scalar) { (code: UInt32) in
var code = (endian == .big) ? code.bigEndian : code.littleEndian
withUnsafeBytes(of: &code) { (buffer) -> Void in
let count = stream.write(buffer.baseAddress!.assumingMemoryBound(to: UInt8.self),
maxLength: buffer.count)
if count != buffer.count {
error = CSVError.cannotWriteStream
}
}
}
if let error = error {
throw error
}
}
}
}
extension CSVWriter {
public func beginNewRow() {
isFirstField = true
}
public func write(field value: String, quoted: Bool = false) throws {
if isFirstRow {
isFirstRow = false
} else {
if isFirstField {
try configuration.newline.unicodeScalars.forEach(writeScalar)
}
}
if isFirstField {
isFirstField = false
} else {
try configuration.delimiter.unicodeScalars.forEach(writeScalar)
}
var value = value
var quoted = quoted
if !quoted {
if value.contains("\"") || value.contains(configuration.delimiter) || value.contains("\r") || value.contains("\n") {
quoted = true
}
}
if quoted {
value = value.replacingOccurrences(of: DQUOTE_STR, with: DQUOTE2_STR)
try writeScalar(DQUOTE)
}
try value.unicodeScalars.forEach(writeScalar)
if quoted {
try writeScalar(DQUOTE)
}
}
public func write(row values: [String], quotedAtIndex: ((Int) -> Bool) = { _ in false }) throws {
beginNewRow()
for (i, value) in values.enumerated() {
try write(field: value, quoted: quotedAtIndex(i))
}
}
}

View File

@ -1,12 +0,0 @@
//
// Legacy.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/11.
// Copyright © 2016 yaslab. All rights reserved.
//
@available(*, deprecated, renamed: "CSVReader")
public typealias CSV = CSVReader
extension CSVReader: Sequence { }

View File

@ -6,24 +6,13 @@
// Copyright © 2016 yaslab. All rights reserved.
//
/// No overview available.
import Foundation
public enum CSVError: Error {
/// No overview available.
case cannotOpenFile
/// No overview available.
case cannotReadFile
/// No overview available.
case cannotWriteStream
/// No overview available.
case streamErrorHasOccurred(error: Error)
/// No overview available.
case unicodeDecoding
/// No overview available.
case cannotReadHeaderRow
/// No overview available.
case stringEncodingMismatch
/// No overview available.
case stringEndianMismatch
}

0
Sources/CSVVersion.h Normal file → Executable file
View File

View File

@ -6,14 +6,8 @@
// Copyright © 2016 yaslab. All rights reserved.
//
/// Represents byte order.
public enum Endian {
/// Big endian.
case big
/// Little endian.
case little
/// Multibyte character sets.
case unknown
}

View File

@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>

View File

@ -6,30 +6,26 @@
// Copyright © 2016 yaslab. All rights reserved.
//
internal class UnicodeIterator<
internal struct UnicodeIterator<
Input: IteratorProtocol,
InputEncoding: UnicodeCodec>: IteratorProtocol
InputEncoding: UnicodeCodec>
: IteratorProtocol
where InputEncoding.CodeUnit == Input.Element {
private var input: Input
private var inputEncoding: InputEncoding
internal var errorHandler: ((Error) -> Void)?
internal init(input: Input, inputEncodingType: InputEncoding.Type) {
self.input = input
self.inputEncoding = inputEncodingType.init()
}
internal func next() -> UnicodeScalar? {
internal mutating func next() -> UnicodeScalar? {
switch inputEncoding.decode(&input) {
case .scalarValue(let c):
return c
case .emptyInput:
return nil
case .error:
errorHandler?(CSVError.unicodeDecoding)
return nil
case .scalarValue(let c): return c
case .emptyInput: return nil
case .error: return nil
}
}
}

View File

@ -0,0 +1,304 @@
//
// CSVReaderTests.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/11.
//
//
import Foundation
import XCTest
@testable import CSV
class CSVReaderTests: XCTestCase {
func test1Line() {
let csv = "abab,cdcd,efef"
let records = parse(csv: csv)
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
}
func testQuoted() {
let csv = "abab,\"cdcd\",efef"
let records = parse(csv: csv)
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
}
func testLF() {
let csv = "abab,cdcd,efef\nzxcv,asdf,qwer"
let records = parse(csv: csv)
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qwer"])
}
func testCommaInQuotationMarks() {
let csv = "abab,\"cd,cd\",efef"
let records = parse(csv: csv)
XCTAssertEqual(records[0], ["abab", "cd,cd", "efef"])
}
func testCRLF() {
let csv = "abab,cdcd,efef\r\nzxcv,asdf,qwer"
let records = parse(csv: csv)
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qwer"])
}
func testEscapedQuotationMark1() {
let csv = "abab,\"\"\"cdcd\",efef\r\nzxcv,asdf,qwer"
let records = parse(csv: csv)
XCTAssertEqual(records[0], ["abab", "\"cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qwer"])
}
func testEscapedQuotationMark2() {
let csv = "abab,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\""
let records = parse(csv: csv)
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er"])
}
func testEmptyField() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let records = parse(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testLastCR() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\",\r"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testLastCRLF() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\",\r\n"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testLastLF() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\",\n"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testLFInQuotationMarks() {
let csv = "abab,,\"\rcdcd\n\",efef\r\nzxcv,asdf,\"qw\"\"er\",\n"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["abab", "", "\rcdcd\n", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testLineBreakLF() {
let csv = "qwe,asd\nzxc,rty"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["qwe", "asd"])
XCTAssertEqual(records[1], ["zxc", "rty"])
}
func testLineBreakCR() {
let csv = "qwe,asd\rzxc,rty"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["qwe", "asd"])
XCTAssertEqual(records[1], ["zxc", "rty"])
}
func testLineBreakCRLF() {
let csv = "qwe,asd\r\nzxc,rty"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["qwe", "asd"])
XCTAssertEqual(records[1], ["zxc", "rty"])
}
func testLineBreakLFLF() {
let csv = "qwe,asd\n\nzxc,rty"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 3)
XCTAssertEqual(records[0], ["qwe", "asd"])
XCTAssertEqual(records[1], [""])
XCTAssertEqual(records[2], ["zxc", "rty"])
}
func testLineBreakCRCR() {
let csv = "qwe,asd\r\rzxc,rty"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 3)
XCTAssertEqual(records[0], ["qwe", "asd"])
XCTAssertEqual(records[1], [""])
XCTAssertEqual(records[2], ["zxc", "rty"])
}
func testLineBreakCRLFCRLF() {
let csv = "qwe,asd\r\n\r\nzxc,rty"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 3)
XCTAssertEqual(records[0], ["qwe", "asd"])
XCTAssertEqual(records[1], [""])
XCTAssertEqual(records[2], ["zxc", "rty"])
}
// func testEncodingWithoutBOM() {
// var index = 0
// let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
// for encoding in allEncodings() {
// print("index: \(index)")
// let records = parse(csv: csv, encoding: encoding)
// XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
// XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
// index += 1
// }
// }
func testUTF8WithBOM() {
let csvString = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = String.Encoding.utf8
var mutableData = Data()
mutableData.append(utf8BOM, count: utf8BOM.count)
mutableData.append(csvString.data(using: encoding)!)
let stream = InputStream(data: mutableData)
let csv = try! CSV(stream: stream, codecType: UTF8.self)
let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testUTF16WithNativeEndianBOM() {
let csvString = "abab,,cdcd,efef\r\nzxcv,😆asdf,\"qw\"\"er\","
let encoding = String.Encoding.utf16
var mutableData = Data()
mutableData.append(csvString.data(using: encoding)!)
let stream = InputStream(data: mutableData as Data)
let csv = try! CSV(stream: stream, codecType: UTF16.self, endian: .unknown)
let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "😆asdf", "qw\"er", ""])
}
func testUTF16WithBigEndianBOM() {
let csvString = "abab,,cdcd,efef\r\n😆zxcv,asdf,\"qw\"\"er\","
let encoding = String.Encoding.utf16BigEndian
var mutableData = Data()
mutableData.append(utf16BigEndianBOM, count: utf16BigEndianBOM.count)
mutableData.append(csvString.data(using: encoding)!)
let stream = InputStream(data: mutableData as Data)
let csv = try! CSV(stream: stream, codecType: UTF16.self, endian: .big)
let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["😆zxcv", "asdf", "qw\"er", ""])
}
func testUTF16WithLittleEndianBOM() {
let csvString = "abab,,cdcd,efef\r\nzxcv😆,asdf,\"qw\"\"er\","
let encoding = String.Encoding.utf16LittleEndian
var mutableData = Data()
mutableData.append(utf16LittleEndianBOM, count: utf16LittleEndianBOM.count)
mutableData.append(csvString.data(using: encoding)!)
let stream = InputStream(data: mutableData as Data)
let csv = try! CSV(stream: stream, codecType: UTF16.self, endian: .little)
let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv😆", "asdf", "qw\"er", ""])
}
func testUTF32WithNativeEndianBOM() {
let csvString = "😆abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = String.Encoding.utf32
var mutableData = Data()
mutableData.append(csvString.data(using: encoding)!)
let stream = InputStream(data: mutableData as Data)
let csv = try! CSV(stream: stream, codecType: UTF32.self, endian: .unknown)
let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["😆abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testUTF32WithBigEndianBOM() {
let csvString = "abab,,cd😆cd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = String.Encoding.utf32BigEndian
var mutableData = Data()
mutableData.append(utf32BigEndianBOM, count: utf32BigEndianBOM.count)
mutableData.append(csvString.data(using: encoding)!)
let stream = InputStream(data: mutableData as Data)
let csv = try! CSV(stream: stream, codecType: UTF32.self, endian: .big)
let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cd😆cd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testUTF32WithLittleEndianBOM() {
let csvString = "abab,,cdcd,ef😆ef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = String.Encoding.utf32LittleEndian
var mutableData = Data()
mutableData.append(utf32LittleEndianBOM, count: utf32LittleEndianBOM.count)
mutableData.append(csvString.data(using: encoding)!)
let stream = InputStream(data: mutableData as Data)
let csv = try! CSV(stream: stream, codecType: UTF32.self, endian: .little)
let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "ef😆ef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
// func allEncodings() -> [String.Encoding] {
// return [
// // multi-byte character encodings
// //String.Encoding.shiftJIS,
// //String.Encoding.japaneseEUC,
// String.Encoding.utf8,
// // wide character encodings
// String.Encoding.utf16BigEndian,
// String.Encoding.utf16LittleEndian,
// String.Encoding.utf32BigEndian,
// String.Encoding.utf32LittleEndian,
// ]
// }
func parse(csv: String) -> [[String]] {
let reader = try! CSV(string: csv)
var records = [[String]]()
for row in reader {
records.append(row)
}
return records
}
func getRecords(csv: CSV) -> [[String]] {
var records = [[String]]()
for row in csv {
records.append(row)
}
return records
}
// func parse(csv: String, encoding: String.Encoding) -> [[String]] {
// let data = csv.data(using: encoding)!
// return parse(data: data, encoding: encoding)
// }
//
// func parse(data: Data, encoding: String.Encoding) -> [[String]] {
// let stream = InputStream(data: data)
// let reader = try! CSV(stream: stream, encoding: encoding)
// var records = [[String]]()
// for row in reader {
// records.append(row)
// }
// return records
// }
static var allTests : [(String, (CSVReaderTests) -> () throws -> Void)] {
return [
//("testExample1", testExample1),
]
}
}

178
Tests/CSV/CSVTests.swift Executable file
View File

@ -0,0 +1,178 @@
//
// CSVTests.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/11.
//
//
import XCTest
@testable import CSV
class CSVTests: XCTestCase {
func test1Line() {
let csv = "\"abc\",1,2"
var i = 0
for row in try! CSV(string: csv) {
switch i {
case 0: XCTAssertEqual(row, ["abc", "1", "2"])
default: break
}
i += 1
}
XCTAssertEqual(i, 1)
}
func test2Lines() {
let csv = "\"abc\",1,2\n\"cde\",3,4"
var i = 0
for row in try! CSV(string: csv) {
switch i {
case 0: XCTAssertEqual(row, ["abc", "1", "2"])
case 1: XCTAssertEqual(row, ["cde", "3", "4"])
default: break
}
i += 1
}
XCTAssertEqual(i, 2)
}
func testLastLineIsEmpty() {
let csv = "\"abc\",1,2\n\"cde\",3,4\n"
var i = 0
for row in try! CSV(string: csv) {
switch i {
case 0: XCTAssertEqual(row, ["abc", "1", "2"])
case 1: XCTAssertEqual(row, ["cde", "3", "4"])
default: break
}
i += 1
}
XCTAssertEqual(i, 2)
}
func testLastLineIsWhiteSpace() {
let csv = "\"abc\",1,2\n\"cde\",3,4\n "
var i = 0
for row in try! CSV(string: csv) {
switch i {
case 0: XCTAssertEqual(row, ["abc", "1", "2"])
case 1: XCTAssertEqual(row, ["cde", "3", "4"])
case 2: XCTAssertEqual(row, [" "])
default: break
}
i += 1
}
XCTAssertEqual(i, 3)
}
func testMiddleLineEmpty() {
let csv = "\"abc\",1,2\n\n\"cde\",3,4"
var i = 0
for row in try! CSV(string: csv) {
switch i {
case 0: XCTAssertEqual(row, ["abc", "1", "2"])
case 1: XCTAssertEqual(row, [""])
case 2: XCTAssertEqual(row, ["cde", "3", "4"])
default: break
}
i += 1
}
XCTAssertEqual(i, 3)
}
func testDoubleQuoteBeforeLineBreak() {
let csv = "\"abc\",1,\"2\"\n\n\"cde\",3,\"4\""
var i = 0
for row in try! CSV(string: csv) {
switch i {
case 0: XCTAssertEqual(row, ["abc", "1", "2"])
case 1: XCTAssertEqual(row, [""])
case 2: XCTAssertEqual(row, ["cde", "3", "4"])
default: break
}
i += 1
}
XCTAssertEqual(i, 3)
}
// func testBufferSizeMod0() {
// let csvString = "0,1,2,3,4,5,6,7,8,9\n"
// let csv = try! CSV(string: csvString, bufferSize: 12)
// XCTAssertEqual(csv.bufferSize, 12)
// }
//
// func testBufferSizeMod1() {
// let csvString = "0,1,2,3,4,5,6,7,8,9\n"
// let csv = try! CSV(string: csvString, bufferSize: 13)
// XCTAssertEqual(csv.bufferSize, 16)
// }
//
// func testBufferSizeMod2() {
// let csvString = "0,1,2,3,4,5,6,7,8,9\n"
// let csv = try! CSV(string: csvString, bufferSize: 14)
// XCTAssertEqual(csv.bufferSize, 16)
// }
//
// func testBufferSizeMod3() {
// let csvString = "0,1,2,3,4,5,6,7,8,9\n"
// let csv = try! CSV(string: csvString, bufferSize: 15)
// XCTAssertEqual(csv.bufferSize, 16)
// }
//
// func testBufferSizeMod4() {
// let csvString = "0,1,2,3,4,5,6,7,8,9\n"
// let csv = try! CSV(string: csvString, bufferSize: 16)
// XCTAssertEqual(csv.bufferSize, 16)
// }
//
// func testBigDataAndSmallBufferSize() {
// let line = "0,1,2,3,4,5,6,7,8,9\n"
// var csv = ""
// for _ in 0..<10000 {
// csv += line
// }
// var i = 0
// for row in try! CSV(string: csv, bufferSize: 10) {
// XCTAssertEqual(row, ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"])
// i += 1
// }
// XCTAssertEqual(i, 10000)
// }
func testSubscript() {
let csvString = "id,name\n001,hoge\n002,fuga"
var csv = try! CSV(string: csvString, hasHeaderRow: true)
var i = 0
while csv.next() != nil {
switch i {
case 0:
XCTAssertEqual(csv["id"], "001")
XCTAssertEqual(csv["name"], "hoge")
case 1:
XCTAssertEqual(csv["id"], "002")
XCTAssertEqual(csv["name"], "fuga")
default:
break
}
i += 1
}
XCTAssertEqual(i, 2)
}
func testCSVState1() {
let it = "あ,い1,\"\",えお\n,,x,".unicodeScalars.makeIterator()
var csv = try! CSV(iterator: it, hasHeaderRow: defaultHasHeaderRow, delimiter: defaultDelimiter)
var rows = [[String]]()
while let row = csv.next() {
rows.append(row)
}
XCTAssertEqual(rows.count, 2)
XCTAssertEqual(rows[0], ["", "い1", "", "えお"])
XCTAssertEqual(rows[1], ["", "", "x", ""])
}
}

62
Tests/CSV/ReadmeTests.swift Executable file
View File

@ -0,0 +1,62 @@
//
// ReadmeTests.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/13.
// Copyright © 2016 yaslab. All rights reserved.
//
import XCTest
@testable import CSV
class ReadmeTests: XCTestCase {
func testFromCSVString() {
for row in try! CSV(string: "1,foo\n2,bar") {
print("\(row)")
// => ["1", "foo"]
// => ["2", "bar"]
}
}
func testFromFilePath() {
// let stream = NSInputStream(fileAtPath: "/path/to/file.csv")!
// for row in try! CSV(stream: stream) {
// print("\(row)")
// }
}
func testGettingTheHeaderRow() {
let csv = try! CSV(
string: "id,name\n1,foo\n2,bar",
hasHeaderRow: true) // default: false
let headerRow = csv.headerRow!
print("\(headerRow)") // => ["id", "name"]
for row in csv {
print("\(row)")
// => ["1", "foo"]
// => ["2", "bar"]
}
}
func testGetTheFieldValueUsingSubscript() {
var csv = try! CSV(
string: "id,name\n1,foo",
hasHeaderRow: true) // It must be true.
while csv.next() != nil {
print("\(csv["id"]!)") // => "1"
print("\(csv["name"]!)") // => "foo"
}
}
func testProvideTheCharacterEncoding() {
// let csv = try! CSV(
// stream: NSInputStream(fileAtPath: "/path/to/file.csv")!,
// codecType: UTF16.self,
// endian: .Big)
}
}

View File

@ -1,105 +0,0 @@
//
// BinaryReaderTests.swift
// CSV
//
// Created by Yasuhiro Hatta on 2018/11/15.
// Copyright © 2018 yaslab. All rights reserved.
//
import XCTest
@testable import CSV
class BinaryReaderTests: XCTestCase {
private func random(_ count: Int) -> [UInt8] {
var array = [UInt8]()
for _ in 0 ..< count {
array.append(UInt8.random(in: .min ... .max))
}
return array
}
func testReadUInt8WithSmallBuffer() {
let bytes = [0xcc] + random(99)
let stream = InputStream(data: Data(bytes))
do {
let reader = try BinaryReader(stream: stream, endian: .unknown, closeOnDeinit: true, bufferSize: 7)
for expected in bytes {
let actual = try reader.readUInt8()
XCTAssertEqual(actual, expected)
}
} catch {
XCTFail("\(error)")
}
}
func testReadUInt16BEWithSmallBuffer() {
let bytes = [0xcc] + random(99)
let stream = InputStream(data: Data(bytes))
do {
let reader = try BinaryReader(stream: stream, endian: .big, closeOnDeinit: true, bufferSize: 7)
for i in stride(from: 0, to: bytes.count, by: 2) {
let expected = (UInt16(bytes[i]) << 8) | UInt16(bytes[i + 1])
let actual = try reader.readUInt16()
XCTAssertEqual(actual, expected)
}
} catch {
XCTFail("\(error)")
}
}
func testReadUInt16LEWithSmallBuffer() {
let bytes = [0xcc] + random(99)
let stream = InputStream(data: Data(bytes))
do {
let reader = try BinaryReader(stream: stream, endian: .little, closeOnDeinit: true, bufferSize: 7)
for i in stride(from: 0, to: bytes.count, by: 2) {
let expected = UInt16(bytes[i]) | (UInt16(bytes[i + 1]) << 8)
let actual = try reader.readUInt16()
XCTAssertEqual(actual, expected)
}
} catch {
XCTFail("\(error)")
}
}
func testReadUInt32BEWithSmallBuffer() {
let bytes = [0xcc] + random(99)
let stream = InputStream(data: Data(bytes))
do {
let reader = try BinaryReader(stream: stream, endian: .big, closeOnDeinit: true, bufferSize: 7)
for i in stride(from: 0, to: bytes.count, by: 4) {
let expected =
(UInt32(bytes[i ]) << 24) | (UInt32(bytes[i + 1]) << 16) |
(UInt32(bytes[i + 2]) << 8) | (UInt32(bytes[i + 3]) )
let actual = try reader.readUInt32()
XCTAssertEqual(actual, expected)
}
} catch {
XCTFail("\(error)")
}
}
func testReadUInt32LEWithSmallBuffer() {
let bytes = [0xcc] + random(99)
let stream = InputStream(data: Data(bytes))
do {
let reader = try BinaryReader(stream: stream, endian: .little, closeOnDeinit: true, bufferSize: 7)
for i in stride(from: 0, to: bytes.count, by: 4) {
let expected =
(UInt32(bytes[i ]) ) | (UInt32(bytes[i + 1]) << 8) |
(UInt32(bytes[i + 2]) << 16) | (UInt32(bytes[i + 3]) << 24)
let actual = try reader.readUInt32()
XCTAssertEqual(actual, expected)
}
} catch {
XCTFail("\(error)")
}
}
}

View File

@ -1,242 +0,0 @@
//
// CSVReaderTests.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/11.
// Copyright © 2016 yaslab. All rights reserved.
//
import XCTest
@testable import CSV
class CSVReaderTests: XCTestCase {
func testOneLine() {
let csv = "\"abc\",1,2"
var i = 0
for record in AnyIterator(try! CSVReader(string: csv)) {
switch i {
case 0: XCTAssertEqual(record, ["abc", "1", "2"])
default: break
}
i += 1
}
XCTAssertEqual(i, 1)
}
func testTwoLines() {
let csv = "\"abc\",1,2\n\"cde\",3,4"
var i = 0
for record in AnyIterator(try! CSVReader(string: csv)) {
switch i {
case 0: XCTAssertEqual(record, ["abc", "1", "2"])
case 1: XCTAssertEqual(record, ["cde", "3", "4"])
default: break
}
i += 1
}
XCTAssertEqual(i, 2)
}
func testLastLineIsEmpty() {
let csv = "\"abc\",1,2\n\"cde\",3,4\n"
var i = 0
for record in AnyIterator(try! CSVReader(string: csv)) {
switch i {
case 0: XCTAssertEqual(record, ["abc", "1", "2"])
case 1: XCTAssertEqual(record, ["cde", "3", "4"])
default: break
}
i += 1
}
XCTAssertEqual(i, 2)
}
func testLastLineIsWhiteSpace() {
let csv = "\"abc\",1,2\n\"cde\",3,4\n "
var i = 0
for record in AnyIterator(try! CSVReader(string: csv)) {
switch i {
case 0: XCTAssertEqual(record, ["abc", "1", "2"])
case 1: XCTAssertEqual(record, ["cde", "3", "4"])
case 2: XCTAssertEqual(record, [" "])
default: break
}
i += 1
}
XCTAssertEqual(i, 3)
}
func testMiddleLineIsEmpty() {
let csv = "\"abc\",1,2\n\n\"cde\",3,4"
var i = 0
for record in AnyIterator(try! CSVReader(string: csv)) {
switch i {
case 0: XCTAssertEqual(record, ["abc", "1", "2"])
case 1: XCTAssertEqual(record, [""])
case 2: XCTAssertEqual(record, ["cde", "3", "4"])
default: break
}
i += 1
}
XCTAssertEqual(i, 3)
}
func testCommaInQuotationMarks() {
let csvString = "abab,\"cd,cd\",efef"
let csv = try! CSVReader(string: csvString)
let record = csv.next()!
XCTAssertEqual(record, ["abab", "cd,cd", "efef"])
}
func testEscapedQuotationMark1() {
let csvString = "abab,\"\"\"cdcd\",efef\r\nzxcv,asdf,qwer"
let csv = try! CSVReader(string: csvString)
var record = csv.next()!
XCTAssertEqual(record, ["abab", "\"cdcd", "efef"])
record = csv.next()!
XCTAssertEqual(record, ["zxcv", "asdf", "qwer"])
}
func testEscapedQuotationMark2() {
let csvString = "abab,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\""
let csv = try! CSVReader(string: csvString)
var record = csv.next()!
XCTAssertEqual(record, ["abab", "cdcd", "efef"])
record = csv.next()!
XCTAssertEqual(record, ["zxcv", "asdf", "qw\"er"])
}
func testEmptyField() {
let csvString = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let csv = try! CSVReader(string: csvString)
var record = csv.next()!
XCTAssertEqual(record, ["abab", "", "cdcd", "efef"])
record = csv.next()!
XCTAssertEqual(record, ["zxcv", "asdf", "qw\"er", ""])
}
func testDoubleQuoteBeforeLineBreak1() {
let csv = "\"abc\",1,\"2\"\n\n\"cde\",3,\"4\""
var i = 0
for record in AnyIterator(try! CSVReader(string: csv)) {
switch i {
case 0: XCTAssertEqual(record, ["abc", "1", "2"])
case 1: XCTAssertEqual(record, [""])
case 2: XCTAssertEqual(record, ["cde", "3", "4"])
default: break
}
i += 1
}
XCTAssertEqual(i, 3)
}
func testDoubleQuoteBeforeLineBreak2() {
let csv = "\"abc\",1,\"2\"\r\n\"cde\",3,\"4\"\r"
var i = 0
for record in AnyIterator(try! CSVReader(string: csv)) {
switch i {
case 0: XCTAssertEqual(record, ["abc", "1", "2"])
case 1: XCTAssertEqual(record, ["cde", "3", "4"])
default: break
}
i += 1
}
XCTAssertEqual(i, 2)
}
func testCSVState1() {
let it = "あ,い1,\"\",えお\n,,x,".unicodeScalars.makeIterator()
let config = CSVReader.Configuration(hasHeaderRow: false,
trimFields: false,
delimiter: ",",
whitespaces: .whitespaces)
let csv = try! CSVReader(iterator: it, configuration: config)
var records = [[String]]()
while let record = csv.next() {
records.append(record)
}
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["", "い1", "", "えお"])
XCTAssertEqual(records[1], ["", "", "x", ""])
}
func testSubscriptInt() {
let csvString = "a,bb,ccc"
let csv = try! CSVReader(string: csvString)
for record in AnyIterator(csv) {
XCTAssertEqual(record[0], "a")
XCTAssertEqual(record[1], "bb")
XCTAssertEqual(record[2], "ccc")
}
}
func testHasHeaderRow1() {
let csvString = "key1,key2\nvalue1,value2"
let csv = try! CSVReader(string: csvString, hasHeaderRow: true)
XCTAssertEqual(csv.headerRow, ["key1", "key2"])
XCTAssertNil(csv.currentRow)
csv.next()
XCTAssertEqual(csv.currentRow, ["value1", "value2"])
}
func testHasHeaderRow2() {
let csvString = "key1,key2\n"
let csv = try! CSVReader(string: csvString, hasHeaderRow: true)
XCTAssertEqual(csv.headerRow, ["key1", "key2"])
XCTAssertNil(csv.currentRow)
csv.next()
XCTAssertNil(csv.currentRow)
}
func testHasHeaderRow3() {
let csvString = "key1,key2"
let csv = try! CSVReader(string: csvString, hasHeaderRow: true)
XCTAssertEqual(csv.headerRow, ["key1", "key2"])
XCTAssertNil(csv.currentRow)
csv.next()
XCTAssertNil(csv.currentRow)
}
func testHasHeaderRow4() {
let csvString = ""
do {
_ = try CSVReader(string: csvString, hasHeaderRow: true)
XCTFail("CSVReader did not throw an error")
} catch CSVError.cannotReadHeaderRow {
// Success
} catch {
XCTFail("\(error)")
}
}
func testSubscript1() {
let csvString = "key1,key2\nvalue1,value2"
let csv = try! CSVReader(string: csvString, hasHeaderRow: true)
csv.next()
XCTAssertEqual(csv["key1"], "value1")
XCTAssertEqual(csv["key2"], "value2")
XCTAssertNil(csv["key9"])
}
func testSubscript2() {
let csvString = "key1,key2\nvalue1"
let csv = try! CSVReader(string: csvString, hasHeaderRow: true)
csv.next()
XCTAssertEqual(csv["key1"], "value1")
XCTAssertEqual(csv["key2"], "")
XCTAssertNil(csv["key9"])
}
func testToArray() {
let csvString = "1,2,3,4,5\n6,7,8,9,0"
let csv = try! CSVReader(string: csvString)
let records = AnyIterator(csv).map { $0 }
XCTAssertEqual(records[0], ["1", "2", "3", "4", "5"])
XCTAssertEqual(records[1], ["6", "7", "8", "9", "0"])
}
}

View File

@ -1,634 +0,0 @@
//
// CSVRowDecoderTests.swift
// CSV
//
// Created by Ian Grossberg on 9/11/18.
// Copyright © 2018 yaslab. All rights reserved.
//
import XCTest
import CSV
//===----------------------------------------------------------------------===//
// Models
//===----------------------------------------------------------------------===//
fileprivate enum Enum: String, Decodable {
case first
case second
}
fileprivate protocol DecodableTest: Equatable {
var intKey: Int { get }
var stringKey: String { get }
var optionalStringKey: String? { get }
var dateKey: Date { get }
var enumKey: Enum { get }
static func headerRow() -> String
func toRow() -> String
}
extension DecodableTest {
fileprivate static func headerRow() -> String {
return "stringKey,optionalStringKey,intKey,ignored,dateKey,enumKey\n"
}
fileprivate func toRow() -> String {
var row = ""
row += "\(self.stringKey),"
row += "\(self.optionalStringKey ?? ""),"
row += "\(self.intKey),"
row += ","
row += "\"\(self.dateKey.timeIntervalSinceReferenceDate)\","
row += "\(self.enumKey.rawValue)"
row += "\n"
return row
}
}
extension Equatable where Self: DecodableTest {
fileprivate static func ==(left: Self, right: Self) -> Bool {
return left.intKey == right.intKey
&& left.stringKey == right.stringKey
&& left.optionalStringKey == right.optionalStringKey
&& Int(left.dateKey.timeIntervalSince1970) == Int(right.dateKey.timeIntervalSince1970)
&& left.enumKey == right.enumKey
}
}
//===----------------------------------------------------------------------===//
// CSVRowDecoderTests
//===----------------------------------------------------------------------===//
class CSVRowDecoderTests: XCTestCase {
//===----------------------------------------------------------------------===//
fileprivate struct SupportedDecodableExample: Decodable, DecodableTest {
let intKey: Int
let stringKey: String
let optionalStringKey: String?
let dateKey: Date
let enumKey: Enum
static var examples: [SupportedDecodableExample] {
return [
SupportedDecodableExample(intKey: 12345, stringKey: "stringValue", optionalStringKey: nil, dateKey: Date(), enumKey: .first),
SupportedDecodableExample(intKey: 54321, stringKey: "stringValue2", optionalStringKey: "withValue", dateKey: Date(timeInterval: 100, since: Date()), enumKey: .second)
]
}
}
func testNoHeader() {
let noHeaderStr = "あ,い1,\"\",えお\n,,x,"
let noHeaderCSV = try! CSVReader(string: noHeaderStr, hasHeaderRow: false)
do {
let decoder = CSVRowDecoder()
let _ = try decoder.decode(SupportedDecodableExample.self, from: noHeaderCSV)
XCTFail("Expect DecodingError.typeMismatch Error thrown")
} catch {
// Success
}
}
func testNumberOfFieldsIsSmall() {
let csv = """
stringKey,intKey,optionalStringKey,dateKey,enumKey
string 0 0 first
string,0,,0,first
"""
let reader = try! CSVReader(string: csv, hasHeaderRow: true)
do {
let decoder = CSVRowDecoder()
if reader.next() != nil {
_ = try decoder.decode(SupportedDecodableExample.self, from: reader)
}
XCTFail("decode<T>() did not threw error")
} catch let DecodingError.valueNotFound(_, context) {
// Success
XCTAssertEqual("intKey", context.codingPath.last!.stringValue)
} catch {
XCTFail("The error thrown is not a DecodingError.valueNotFound")
}
}
func testStringCodingKey() {
let exampleRecords = SupportedDecodableExample.examples
let header = SupportedDecodableExample.headerRow()
let allRows = exampleRecords.reduce(into: header) { $0 += $1.toRow() }
let headerCSV = try! CSVReader(string: allRows, hasHeaderRow: true)
var records = [SupportedDecodableExample]()
do {
let decoder = CSVRowDecoder()
while headerCSV.next() != nil {
try records.append(decoder.decode(SupportedDecodableExample.self, from: headerCSV))
}
} catch {
XCTFail("decode<T>() threw error: \(error)")
return
}
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], exampleRecords[0])
XCTAssertEqual(records[1], exampleRecords[1])
}
func testTypeInvalidDateFormat() {
let invalidFieldTypeStr = """
dateKey,stringKey,optionalStringKey,intKey,ignored
al;ksdjf;akjsdf,asldkj,,1234,
"""
let invalidFieldTypeCSV = try! CSVReader(string: invalidFieldTypeStr, hasHeaderRow: true)
do {
let decoder = CSVRowDecoder()
while invalidFieldTypeCSV.next() != nil {
_ = try decoder.decode(SupportedDecodableExample.self, from: invalidFieldTypeCSV)
}
XCTFail("Expect DecodingError.dataCorrupted Error thrown")
} catch {
guard let error = error as? DecodingError else {
XCTFail("Expect DecodingError Error thrown")
return
}
switch error {
case let DecodingError.typeMismatch(type, context):
XCTAssert(type == Double.self)
XCTAssertEqual(context.codingPath[0].stringValue, "dateKey", "Type Mismatch Error on unexpected field")
default:
XCTFail("Expect DecodingError.dataCorrupted Error thrown, got \(error)")
}
}
}
//===----------------------------------------------------------------------===//
fileprivate struct IntKeyedDecodableExample: Decodable, DecodableTest {
private enum CodingKeys: Int, CodingKey {
case stringKey = 0
case optionalStringKey = 1
case intKey = 2
case dateKey = 4
case enumKey = 5
}
let intKey: Int
let stringKey: String
let optionalStringKey: String?
let dateKey: Date
let enumKey: Enum
static var examples: [IntKeyedDecodableExample] {
return [
IntKeyedDecodableExample(intKey: 12345, stringKey: "stringValue", optionalStringKey: nil, dateKey: Date(), enumKey: .first),
IntKeyedDecodableExample(intKey: 54321, stringKey: "stringValue2", optionalStringKey: "withValue", dateKey: Date(timeInterval: 100, since: Date()), enumKey: .second)
]
}
}
func testIntCodingKey() {
let exampleRecords = IntKeyedDecodableExample.examples
let allRows = IntKeyedDecodableExample.examples.reduce(into: "") { $0 += $1.toRow() }
let headerCSV = try! CSVReader(string: allRows, hasHeaderRow: false)
var records = [IntKeyedDecodableExample]()
do {
let decoder = CSVRowDecoder()
while headerCSV.next() != nil {
try records.append(decoder.decode(IntKeyedDecodableExample.self, from: headerCSV))
}
} catch {
XCTFail("decode<T>() threw error: \(error)")
return
}
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], exampleRecords[0])
XCTAssertEqual(records[1], exampleRecords[1])
}
func testIntCodingKeyWhileIgnoringHeaders() {
let exampleRecords = IntKeyedDecodableExample.examples
let header = IntKeyedDecodableExample.headerRow()
let allRows = exampleRecords.reduce(into: header) { $0 += $1.toRow() }
let headerCSV = try! CSVReader(string: allRows, hasHeaderRow: true)
var records = [IntKeyedDecodableExample]()
do {
let decoder = CSVRowDecoder()
while headerCSV.next() != nil {
try records.append(decoder.decode(IntKeyedDecodableExample.self, from: headerCSV))
}
} catch {
XCTFail("decode<T>() threw error: \(error)")
return
}
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], exampleRecords[0])
XCTAssertEqual(records[1], exampleRecords[1])
}
func testTypeMismatch() {
let exampleRecords = SupportedDecodableExample.examples
let invalidFieldTypeStr = """
stringKey,optionalStringKey,intKey,ignored
\(exampleRecords[0].stringKey),,this is a string where we expect an Int,
\(exampleRecords[1].stringKey),\(exampleRecords[1].optionalStringKey!),\(exampleRecords[1].intKey),
"""
let invalidFieldTypeCSV = try! CSVReader(string: invalidFieldTypeStr, hasHeaderRow: true)
do {
let decoder = CSVRowDecoder()
while invalidFieldTypeCSV.next() != nil {
_ = try decoder.decode(IntKeyedDecodableExample.self, from: invalidFieldTypeCSV)
}
XCTFail("Expect DecodingError.typeMismatch Error thrown")
} catch {
guard let error = error as? DecodingError else {
XCTFail("Expect DecodingError Error thrown")
return
}
switch error {
case let .typeMismatch(_, context):
XCTAssertEqual(context.codingPath[0].stringValue, "intKey", "Type Mismatch Error on unexpected field")
default:
XCTFail("Expect Type Mismatch Error thrown")
}
}
}
//===----------------------------------------------------------------------===//
fileprivate struct UnsupportedDecodableExample: Decodable, Equatable {
let enumKey: Enum
static var examples: [UnsupportedDecodableExample] {
return [
UnsupportedDecodableExample(enumKey: .first),
UnsupportedDecodableExample(enumKey: .second)
]
}
}
func testUnsupportedDecodableField() {
let exampleRecords = UnsupportedDecodableExample.examples
let headerStr = """
enumKey,optionalStringKey,intKey,ignored,dateKey
\(exampleRecords[0].enumKey),"hiiiii",123445,,
\(exampleRecords[1].enumKey),,54231,,
\("third"),,54231,,
"""
let headerCSV = try! CSVReader(string: headerStr, hasHeaderRow: true)
var records = [UnsupportedDecodableExample]()
do {
let decoder = CSVRowDecoder()
while headerCSV.next() != nil {
try records.append(decoder.decode(UnsupportedDecodableExample.self, from: headerCSV))
}
XCTFail("Expect Data Corrupted Error thrown")
} catch {
XCTAssertEqual(records.count, 2)
guard let decodingError = error as? DecodingError else {
XCTFail("Expect DecodingError Error thrown, instead we go \(error)")
return
}
switch decodingError {
case let .dataCorrupted(context):
guard context.codingPath[0].stringValue == "enumKey" else {
XCTFail("Data Corrupted Error on unexpected field")
return
}
default:
XCTFail("Expect Data Corrupted Error thrown, instead we got \(decodingError)")
}
}
}
//===----------------------------------------------------------------------===//
fileprivate struct IntegerDecodableExample: Decodable {
let intValue: Int
let int8Value: Int8
let int16Value: Int16
let int32Value: Int32
let int64Value: Int64
let uintValue: UInt
let uint8Value: UInt8
let uint16Value: UInt16
let uint32Value: UInt32
let uint64Value: UInt64
}
func testDecodeInteger() {
let csv = """
intValue,int8Value,int16Value,int32Value,int64Value,uintValue,uint8Value,uint16Value,uint32Value,uint64Value
0,123,4567,89012,345678901234567890,1,124,4568,89013,345678901234567891
"""
do {
let reader = try CSVReader(string: csv, hasHeaderRow: true)
reader.next()
let decoder = CSVRowDecoder()
let row = try decoder.decode(IntegerDecodableExample.self, from: reader)
XCTAssertEqual(row.intValue, 0)
XCTAssertEqual(row.int8Value, 123)
XCTAssertEqual(row.int16Value, 4567)
XCTAssertEqual(row.int32Value, 89012)
XCTAssertEqual(row.int64Value, 345678901234567890)
XCTAssertEqual(row.uintValue, 1)
XCTAssertEqual(row.uint8Value, 124)
XCTAssertEqual(row.uint16Value, 4568)
XCTAssertEqual(row.uint32Value, 89013)
XCTAssertEqual(row.uint64Value, 345678901234567891)
} catch {
XCTFail("\(error)")
}
}
//===----------------------------------------------------------------------===//
fileprivate struct FloatDecodableExample: Decodable {
let floatValue: Float
let doubleValue: Double
}
func testDecodeFloat() {
let csv = """
floatValue,doubleValue
123.456,7890.1234
"""
do {
let reader = try CSVReader(string: csv, hasHeaderRow: true)
reader.next()
let decoder = CSVRowDecoder()
let row = try decoder.decode(FloatDecodableExample.self, from: reader)
XCTAssertEqual(row.floatValue, 123.456)
XCTAssertEqual(row.doubleValue, 7890.1234)
} catch {
XCTFail("\(error)")
}
}
//===----------------------------------------------------------------------===//
fileprivate struct BoolDecodingStrategyExample: Decodable {
let falseValue: Bool
let trueValue: Bool
}
func testBoolDecodingStrategy_default() {
let csv = """
falseValue,trueValue
false,true
"""
do {
let reader = try CSVReader(string: csv, hasHeaderRow: true)
reader.next()
let decoder = CSVRowDecoder()
decoder.boolDecodingStrategy = .default
let row = try decoder.decode(BoolDecodingStrategyExample.self, from: reader)
XCTAssertEqual(row.falseValue, false)
XCTAssertEqual(row.trueValue, true)
} catch {
XCTFail("\(error)")
}
}
func testBoolDecodingStrategy_custom() {
let csv = """
falseValue,trueValue
0,1
"""
do {
let reader = try CSVReader(string: csv, hasHeaderRow: true)
reader.next()
let decoder = CSVRowDecoder()
decoder.boolDecodingStrategy = .custom({ $0 != "0" })
let row = try decoder.decode(BoolDecodingStrategyExample.self, from: reader)
XCTAssertEqual(row.falseValue, false)
XCTAssertEqual(row.trueValue, true)
} catch {
XCTFail("\(error)")
}
}
//===----------------------------------------------------------------------===//
fileprivate struct DateDecodingStrategyExample: Decodable {
let date: Date
}
func testDateDecodingStrategy_deferredToDate() {
let expected = Date()
let csv = """
date
\(expected.timeIntervalSinceReferenceDate)
"""
do {
let reader = try CSVReader(string: csv, hasHeaderRow: true)
reader.next()
let decoder = CSVRowDecoder()
decoder.dateDecodingStrategy = .deferredToDate
let row = try decoder.decode(DateDecodingStrategyExample.self, from: reader)
XCTAssertEqual(row.date, expected)
} catch {
XCTFail("\(error)")
}
}
func testDateDecodingStrategy_secondsSince1970() {
let expected = Date()
let csv = """
date
\(expected.timeIntervalSince1970)
"""
do {
let reader = try CSVReader(string: csv, hasHeaderRow: true)
reader.next()
let decoder = CSVRowDecoder()
decoder.dateDecodingStrategy = .secondsSince1970
let row = try decoder.decode(DateDecodingStrategyExample.self, from: reader)
XCTAssertEqual(row.date.timeIntervalSince1970, expected.timeIntervalSince1970)
} catch {
XCTFail("\(error)")
}
}
func testDateDecodingStrategy_millisecondsSince1970() {
let expected = Date()
let csv = """
date
\(expected.timeIntervalSince1970 * 1000.0)
"""
do {
let reader = try CSVReader(string: csv, hasHeaderRow: true)
reader.next()
let decoder = CSVRowDecoder()
decoder.dateDecodingStrategy = .millisecondsSince1970
let row = try decoder.decode(DateDecodingStrategyExample.self, from: reader)
XCTAssertEqual(row.date.timeIntervalSince1970, expected.timeIntervalSince1970)
} catch {
XCTFail("\(error)")
}
}
@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
func testDateDecodingStrategy_iso8601() {
let csv = """
date
2018-11-22T12:34:56+09:00
"""
do {
let reader = try CSVReader(string: csv, hasHeaderRow: true)
reader.next()
let decoder = CSVRowDecoder()
decoder.dateDecodingStrategy = .iso8601
let row = try decoder.decode(DateDecodingStrategyExample.self, from: reader)
XCTAssertEqual(row.date.timeIntervalSince1970, 1542857696)
} catch {
XCTFail("\(error)")
}
}
func testDateDecodingStrategy_formatted() {
let csv = """
date
2018/11/22
"""
do {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(identifier: "Asia/Tokyo")
formatter.dateFormat = "yyyy/MM/dd"
let reader = try CSVReader(string: csv, hasHeaderRow: true)
reader.next()
let decoder = CSVRowDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)
let row = try decoder.decode(DateDecodingStrategyExample.self, from: reader)
XCTAssertEqual(row.date.timeIntervalSince1970, 1542812400)
} catch {
XCTFail("\(error)")
}
}
func testDateDecodingStrategy_custom() {
let expected = Date()
let csv = """
date
\(expected.timeIntervalSinceReferenceDate)
"""
do {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(identifier: "Asia/Tokyo")
formatter.dateFormat = "yyyy/MM/dd"
let reader = try CSVReader(string: csv, hasHeaderRow: true)
reader.next()
let decoder = CSVRowDecoder()
decoder.dateDecodingStrategy = .custom({ Date(timeIntervalSinceReferenceDate: Double($0)!) })
let row = try decoder.decode(DateDecodingStrategyExample.self, from: reader)
XCTAssertEqual(row.date, expected)
} catch {
XCTFail("\(error)")
}
}
//===----------------------------------------------------------------------===//
fileprivate struct DataDecodingStrategyExample: Decodable {
let data: Data
}
func testDataDecodingStrategy_base64() {
let expected = Data([0x56, 0x12, 0x00, 0x34, 0x1a, 0xfe])
let csv = """
data
"\(expected.base64EncodedString())"
"""
do {
let reader = try CSVReader(string: csv, hasHeaderRow: true)
reader.next()
let decoder = CSVRowDecoder()
decoder.dataDecodingStrategy = .base64
let row = try decoder.decode(DataDecodingStrategyExample.self, from: reader)
XCTAssertEqual(row.data, expected)
} catch {
XCTFail("\(error)")
}
}
func testDataDecodingStrategy_custom() {
let expected = Data([0x34, 0x1a, 0xfe, 0x56, 0x12, 0x00])
let csv = """
data
"\(expected.map({ String(format: "%02x", $0) }).joined())"
"""
do {
let reader = try CSVReader(string: csv, hasHeaderRow: true)
reader.next()
let decoder = CSVRowDecoder()
decoder.dataDecodingStrategy = .custom { value in
var bytes = [UInt8]()
for i in stride(from: 0, to: value.count, by: 2) {
let start = value.index(value.startIndex, offsetBy: i)
let end = value.index(value.startIndex, offsetBy: i + 1)
bytes.append(UInt8(value[start...end], radix: 16)!)
}
return Data(bytes)
}
let row = try decoder.decode(DataDecodingStrategyExample.self, from: reader)
XCTAssertEqual(row.data, expected)
} catch {
XCTFail("\(error)")
}
}
//===----------------------------------------------------------------------===//
fileprivate struct FoundationDecodingExample: Decodable {
let url: URL
let decimal: Decimal
}
func testFoundationDecoding() {
let csv = """
url,decimal
"https://www.example.com/path?param=1",99999999999999999999.9999999999999999
"""
do {
let reader = try CSVReader(string: csv, hasHeaderRow: true)
reader.next()
let decoder = CSVRowDecoder()
let row = try decoder.decode(FoundationDecodingExample.self, from: reader)
XCTAssertEqual(row.url.absoluteString, "https://www.example.com/path?param=1")
XCTAssertEqual(row.decimal.description, "99999999999999999999.9999999999999999")
} catch {
XCTFail("\(error)")
}
}
}

View File

@ -1,336 +0,0 @@
//
// CSVWriterTests.swift
// CSV
//
// Created by Yasuhiro Hatta on 2017/05/28.
// Copyright © 2017 yaslab. All rights reserved.
//
import Foundation
import XCTest
import CSV
extension OutputStream {
var data: Data? {
return self.property(forKey: .dataWrittenToMemoryStreamKey) as? Data
}
}
class CSVWriterTests: XCTestCase {
let str = "TEST-test-1234-😄😆👨‍👩‍👧‍👦"
/// xxxx
func testSingleFieldSingleRecord() {
let csv = try! CSVWriter(stream: .toMemory())
csv.beginNewRow()
try! csv.write(field: str)
let data = csv.stream.data!
let csvStr = String(data: data, encoding: .utf8)!
XCTAssertEqual(csvStr, str)
}
/// xxxx
/// xxxx
func testSingleFieldMultipleRecord() {
let stream = OutputStream.toMemory()
stream.open()
let csv = try! CSVWriter(stream: stream)
csv.beginNewRow()
try! csv.write(field: str + "-1")
csv.beginNewRow()
try! csv.write(field: str + "-2")
stream.close()
let data = stream.data!
let csvStr = String(data: data, encoding: .utf8)!
XCTAssertEqual(csvStr, "\(str)-1\n\(str)-2")
}
/// xxxx,xxxx
func testMultipleFieldSingleRecord() {
let stream = OutputStream.toMemory()
stream.open()
let csv = try! CSVWriter(stream: stream)
csv.beginNewRow()
try! csv.write(field: str + "-1")
try! csv.write(field: str + "-2")
stream.close()
let data = stream.data!
let csvStr = String(data: data, encoding: .utf8)!
XCTAssertEqual(csvStr, "\(str)-1,\(str)-2")
}
/// xxxx,xxxx
/// xxxx,xxxx
func testMultipleFieldMultipleRecord() {
let stream = OutputStream.toMemory()
stream.open()
let csv = try! CSVWriter(stream: stream)
csv.beginNewRow()
try! csv.write(field: str + "-1-1")
try! csv.write(field: str + "-1-2")
csv.beginNewRow()
try! csv.write(field: str + "-2-1")
try! csv.write(field: str + "-2-2")
stream.close()
let data = stream.data!
let csvStr = String(data: data, encoding: .utf8)!
XCTAssertEqual(csvStr, "\(str)-1-1,\(str)-1-2\n\(str)-2-1,\(str)-2-2")
}
/// "xxxx",xxxx
func testQuoted() {
let stream = OutputStream.toMemory()
stream.open()
let csv = try! CSVWriter(stream: stream)
csv.beginNewRow()
try! csv.write(field: str + "-1", quoted: true)
try! csv.write(field: str + "-2") // quoted: false
stream.close()
let data = stream.data!
let csvStr = String(data: data, encoding: .utf8)!
XCTAssertEqual(csvStr, "\"\(str)-1\",\(str)-2")
}
/// xxxx,"xx\nxx"
func testQuotedNewline() {
let stream = OutputStream.toMemory()
stream.open()
let csv = try! CSVWriter(stream: stream)
csv.beginNewRow()
try! csv.write(field: str + "-1") // quoted: false
try! csv.write(field: str + "-\n-2", quoted: true)
stream.close()
let data = stream.data!
let csvStr = String(data: data, encoding: .utf8)!
XCTAssertEqual(csvStr, "\(str)-1,\"\(str)-\n-2\"")
}
/// xxxx,"xx""xx"
func testEscapeQuote() {
let stream = OutputStream.toMemory()
stream.open()
let csv = try! CSVWriter(stream: stream)
csv.beginNewRow()
try! csv.write(field: str + "-1") // quoted: false
try! csv.write(field: str + "-\"-2", quoted: true)
stream.close()
let data = stream.data!
let csvStr = String(data: data, encoding: .utf8)!
XCTAssertEqual(csvStr, "\(str)-1,\"\(str)-\"\"-2\"")
}
/// csv.write(row: ["xxxx", "xx,\"xx"])
/// -> xxxx,"xx,""xx"
func testEscapeQuoteAutomatically() {
let stream = OutputStream.toMemory()
stream.open()
let csv = try! CSVWriter(stream: stream)
try! csv.write(row: ["id", "testing,\"comma"]) // quoted: false
stream.close()
let data = stream.data!
let csvStr = String(data: data, encoding: .utf8)!
XCTAssertEqual(csvStr, "id,\"testing,\"\"comma\"")
}
/// csv.write(row: ["xxxx", "xx\rxx", "xx\nxx", "xx\r\nrxx"])
/// -> xxxx,"xx\rxx","xx\nxx","xx\r\nxx"
func testEscapeNewlineAutomatically() {
let stream = OutputStream.toMemory()
stream.open()
let csv = try! CSVWriter(stream: stream)
try! csv.write(row: ["id", "testing\rCR", "testing\nLF", "testing\r\nCRLF"]) // quoted: false
stream.close()
let data = stream.data!
let csvStr = String(data: data, encoding: .utf8)!
XCTAssertEqual(csvStr, "id,\"testing\rCR\",\"testing\nLF\",\"testing\r\nCRLF\"")
}
/// Test delimiter: $
/// csv.write(row: ["xxxx", "xx$xx"])
/// -> xxxx$"xx$xx"
func testEscapeDelimiterAutomatically() {
let stream = OutputStream.toMemory()
stream.open()
let csv = try! CSVWriter(stream: stream, delimiter: "$")
try! csv.write(row: ["id", "testing$dollar"]) // quoted: false
stream.close()
let data = stream.data!
let csvStr = String(data: data, encoding: .utf8)!
XCTAssertEqual(csvStr, "id$\"testing$dollar\"")
}
/// Test delimiter: "\t"
func testDelimiter() {
let stream = OutputStream.toMemory()
stream.open()
let csv = try! CSVWriter.init(stream: stream, delimiter: "\t")
csv.beginNewRow()
try! csv.write(field: str + "-1")
try! csv.write(field: str + "-2")
stream.close()
let data = stream.data!
let csvStr = String(data: data, encoding: .utf8)!
XCTAssertEqual(csvStr, "\(str)-1\t\(str)-2")
}
/// Test newline: "\r\n"
func testNewline() {
let stream = OutputStream.toMemory()
stream.open()
let csv = try! CSVWriter.init(stream: stream, newline: .crlf)
csv.beginNewRow()
try! csv.write(field: str + "-1")
csv.beginNewRow()
try! csv.write(field: str + "-2")
stream.close()
let data = stream.data!
let csvStr = String(data: data, encoding: .utf8)!
XCTAssertEqual(csvStr, "\(str)-1\r\n\(str)-2")
}
/// xxxx,xxxx
func testValueContainsComma() {
let stream = OutputStream.toMemory()
stream.open()
let csv = try! CSVWriter(stream: stream)
csv.beginNewRow()
try! csv.write(field: str + ",1", quoted: true)
try! csv.write(field: str + ",2") // quoted: false
stream.close()
let data = stream.data!
let csvStr = String(data: data, encoding: .utf8)!
XCTAssertEqual(csvStr, "\"\(str),1\",\"\(str),2\"")
}
/// UTF16 Big Endian
func testUTF16BE() {
let stream = OutputStream.toMemory()
stream.open()
let csv = try! CSVWriter(stream: stream, codecType: UTF16.self, endian: .big)
csv.beginNewRow()
try! csv.write(field: str)
stream.close()
let data = stream.data!
let csvStr = String(data: data, encoding: .utf16BigEndian)!
XCTAssertEqual(csvStr, str)
}
/// UTF16 Little Endian
func testUTF16LE() {
let stream = OutputStream.toMemory()
stream.open()
let csv = try! CSVWriter(stream: stream, codecType: UTF16.self, endian: .little)
csv.beginNewRow()
try! csv.write(field: str)
stream.close()
let data = stream.data!
let csvStr = String(data: data, encoding: .utf16LittleEndian)!
XCTAssertEqual(csvStr, str)
}
/// UTF32 Big Endian
func testUTF32BE() {
let stream = OutputStream.toMemory()
stream.open()
let csv = try! CSVWriter(stream: stream, codecType: UTF32.self, endian: .big)
csv.beginNewRow()
try! csv.write(field: str)
stream.close()
let data = stream.data!
let csvStr = String(data: data, encoding: .utf32BigEndian)!
XCTAssertEqual(csvStr, str)
}
/// UTF32 Little Endian
func testUTF32LE() {
let stream = OutputStream.toMemory()
stream.open()
let csv = try! CSVWriter(stream: stream, codecType: UTF32.self, endian: .little)
csv.beginNewRow()
try! csv.write(field: str)
stream.close()
let data = stream.data!
let csvStr = String(data: data, encoding: .utf32LittleEndian)!
XCTAssertEqual(csvStr, str)
}
func testReadme() {
let csv = try! CSVWriter(stream: .toMemory())
// Write a row
try! csv.write(row: ["id", "name"])
// Write fields separately
csv.beginNewRow()
try! csv.write(field: "1")
try! csv.write(field: "foo")
csv.beginNewRow()
try! csv.write(field: "2")
try! csv.write(field: "bar")
csv.stream.close()
// Get a String
let csvData = csv.stream.property(forKey: .dataWrittenToMemoryStreamKey) as! Data
let csvString = String(data: csvData, encoding: .utf8)!
print(csvString)
// => "id,name\n1,foo\n2,bar"
XCTAssertEqual("id,name\n1,foo\n2,bar", csvString)
}
}

View File

@ -1,121 +0,0 @@
//
// LineBreakTests.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/11.
// Copyright © 2016 yaslab. All rights reserved.
//
import XCTest
@testable import CSV
class LineBreakTests: XCTestCase {
func testLF() {
let csv = "abab,cdcd,efef\nzxcv,asdf,qwer"
let records = parse(csv: csv)
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qwer"])
}
func testCRLF() {
let csv = "abab,cdcd,efef\r\nzxcv,asdf,qwer"
let records = parse(csv: csv)
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qwer"])
}
func testLastCR() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\",\r"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testLastCRLF() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\",\r\n"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testLastLF() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\",\n"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testLFInQuotationMarks() {
let csv = "abab,,\"\rcdcd\n\",efef\r\nzxcv,asdf,\"qw\"\"er\",\n"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["abab", "", "\rcdcd\n", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testLineBreakLF() {
let csv = "qwe,asd\nzxc,rty"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["qwe", "asd"])
XCTAssertEqual(records[1], ["zxc", "rty"])
}
func testLineBreakCR() {
let csv = "qwe,asd\rzxc,rty"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["qwe", "asd"])
XCTAssertEqual(records[1], ["zxc", "rty"])
}
func testLineBreakCRLF() {
let csv = "qwe,asd\r\nzxc,rty"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["qwe", "asd"])
XCTAssertEqual(records[1], ["zxc", "rty"])
}
func testLineBreakLFLF() {
let csv = "qwe,asd\n\nzxc,rty"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 3)
XCTAssertEqual(records[0], ["qwe", "asd"])
XCTAssertEqual(records[1], [""])
XCTAssertEqual(records[2], ["zxc", "rty"])
}
func testLineBreakCRCR() {
let csv = "qwe,asd\r\rzxc,rty"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 3)
XCTAssertEqual(records[0], ["qwe", "asd"])
XCTAssertEqual(records[1], [""])
XCTAssertEqual(records[2], ["zxc", "rty"])
}
func testLineBreakCRLFCRLF() {
let csv = "qwe,asd\r\n\r\nzxc,rty"
let records = parse(csv: csv)
XCTAssertEqual(records.count, 3)
XCTAssertEqual(records[0], ["qwe", "asd"])
XCTAssertEqual(records[1], [""])
XCTAssertEqual(records[2], ["zxc", "rty"])
}
private func parse(csv: String) -> [[String]] {
let reader = try! CSVReader(string: csv)
return reader.map { $0 }
// var records = [[String]]()
// try! reader.enumerateRows { (row, _, _) in
// records.append(row)
// }
// return records
}
}

View File

@ -1,104 +0,0 @@
//
// ReadmeTests.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/13.
// Copyright © 2016 yaslab. All rights reserved.
//
import XCTest
@testable import CSV
class ReadmeTests: XCTestCase {
// MARK: - Reading
func testFromCSVString() {
let csvString = "1,foo\n2,bar"
let csv = try! CSVReader(string: csvString)
while let row = csv.next() {
print("\(row)")
}
// => ["1", "foo"]
// => ["2", "bar"]
}
func testFromFile() {
// let stream = InputStream(fileAtPath: "/path/to/file.csv")!
// let csv = try! CSVReader(stream: stream)
// while let row = csv.next() {
// print("\(row)")
// }
}
func testGettingTheHeaderRow() {
let csvString = "id,name\n1,foo\n2,bar"
let csv = try! CSVReader(string: csvString,
hasHeaderRow: true) // It must be true.
let headerRow = csv.headerRow!
print("\(headerRow)") // => ["id", "name"]
while let row = csv.next() {
print("\(row)")
}
// => ["1", "foo"]
// => ["2", "bar"]
}
func testGetTheFieldValueUsingKey() {
let csvString = "id,name\n1,foo"
let csv = try! CSVReader(string: csvString,
hasHeaderRow: true) // It must be true.
while csv.next() != nil {
print("\(csv["id"]!)") // => "1"
print("\(csv["name"]!)") // => "foo"
}
}
func testProvideTheCharacterEncoding() {
// let stream = InputStream(fileAtPath: "/path/to/file.csv")!
// let csv = try! CSVReader(stream: stream,
// codecType: UTF16.self,
// endian: .big)
}
// MARK: - Writing
func testWriteToMemory() {
let stream = OutputStream(toMemory: ())
let csv = try! CSVWriter(stream: stream)
// Write a row
try! csv.write(row: ["id", "name"])
// Write fields separately
csv.beginNewRow()
try! csv.write(field: "1")
try! csv.write(field: "foo")
csv.beginNewRow()
try! csv.write(field: "2")
try! csv.write(field: "bar")
csv.stream.close()
// Get a String
let csvData = stream.property(forKey: .dataWrittenToMemoryStreamKey) as! NSData
let csvString = String(data: Data(referencing: csvData), encoding: .utf8)!
print(csvString)
// => "id,name\n1,foo\n2,bar"
}
func testWriteToFile() {
// let stream = OutputStream(toFileAtPath: "/path/to/file.csv", append: false)!
// let csv = try! CSVWriter(stream: stream)
//
// try! csv.write(row: ["id", "name"])
// try! csv.write(row: ["1", "foo"])
// try! csv.write(row: ["1", "bar"])
//
// csv.stream.close()
}
}

View File

@ -1,167 +0,0 @@
//
// TrimFieldsTests.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/10/18.
// Copyright © 2016 yaslab. All rights reserved.
//
import XCTest
@testable import CSV
class TrimFieldsTests: XCTestCase {
func testTrimFields1() {
let csvString = "abc,def,ghi"
let csv = try! CSVReader(string: csvString, trimFields: true)
for record in AnyIterator(csv) {
XCTAssertEqual(record, ["abc", "def", "ghi"])
}
}
func testTrimFields2() {
let csvString = " abc, def, ghi"
let csv = try! CSVReader(string: csvString, trimFields: true)
for record in AnyIterator(csv) {
XCTAssertEqual(record, ["abc", "def", "ghi"])
}
}
func testTrimFields3() {
let csvString = "abc ,def ,ghi "
let csv = try! CSVReader(string: csvString, trimFields: true)
for record in AnyIterator(csv) {
XCTAssertEqual(record, ["abc", "def", "ghi"])
}
}
func testTrimFields4() {
let csvString = " abc , def , ghi "
let csv = try! CSVReader(string: csvString, trimFields: true)
for record in AnyIterator(csv) {
XCTAssertEqual(record, ["abc", "def", "ghi"])
}
}
func testTrimFields5() {
let csvString = "\"abc\",\"def\",\"ghi\""
let csv = try! CSVReader(string: csvString, trimFields: true)
for record in AnyIterator(csv) {
XCTAssertEqual(record, ["abc", "def", "ghi"])
}
}
func testTrimFields6() {
let csvString = " \"abc\", \"def\", \"ghi\""
let csv = try! CSVReader(string: csvString, trimFields: true)
for record in AnyIterator(csv) {
XCTAssertEqual(record, ["abc", "def", "ghi"])
}
}
func testTrimFields7() {
let csvString = "\"abc\" ,\"def\" ,\"ghi\" "
let csv = try! CSVReader(string: csvString, trimFields: true)
for record in AnyIterator(csv) {
XCTAssertEqual(record, ["abc", "def", "ghi"])
}
}
func testTrimFields8() {
let csvString = " \"abc\" , \"def\" , \"ghi\" "
let csv = try! CSVReader(string: csvString, trimFields: true)
for record in AnyIterator(csv) {
XCTAssertEqual(record, ["abc", "def", "ghi"])
}
}
func testTrimFields9() {
let csvString = "\" abc \",\" def \",\" ghi \""
let csv = try! CSVReader(string: csvString, trimFields: true)
for record in AnyIterator(csv) {
XCTAssertEqual(record, [" abc ", " def ", " ghi "])
}
}
func testTrimFields10() {
let csvString = "\tabc,\t\tdef\t,ghi\t"
let csv = try! CSVReader(string: csvString, trimFields: true)
for record in AnyIterator(csv) {
XCTAssertEqual(record, ["abc", "def", "ghi"])
}
}
func testTrimFields11() {
let csvString = " abc \n def "
let csv = try! CSVReader(string: csvString, trimFields: true)
let record1 = csv.next()!
XCTAssertEqual(record1, ["abc"])
let record2 = csv.next()!
XCTAssertEqual(record2, ["def"])
}
func testTrimFields12() {
let csvString = " \"abc \" \n \" def\" "
let csv = try! CSVReader(string: csvString, trimFields: true)
let record1 = csv.next()!
XCTAssertEqual(record1, ["abc "])
let record2 = csv.next()!
XCTAssertEqual(record2, [" def"])
}
func testTrimFields13() {
let csvString = " abc \t\tdef\t ghi "
let csv = try! CSVReader(string: csvString, trimFields: true, delimiter: "\t")
for record in AnyIterator(csv) {
XCTAssertEqual(record, ["abc", "", "def", "ghi"])
}
}
func testTrimFields14() {
let csvString = ""
let csv = try! CSVReader(string: csvString, trimFields: true)
let records = AnyIterator(csv).map { $0 }
XCTAssertEqual(records.count, 0)
}
func testTrimFields15() {
let csvString = " "
let csv = try! CSVReader(string: csvString, trimFields: true)
let records = AnyIterator(csv).map { $0 }
XCTAssertEqual(records.count, 1)
XCTAssertEqual(records[0], [""])
}
func testTrimFields16() {
let csvString = " , "
let csv = try! CSVReader(string: csvString, trimFields: true)
let records = AnyIterator(csv).map { $0 }
XCTAssertEqual(records.count, 1)
XCTAssertEqual(records[0], ["", ""])
}
func testTrimFields17() {
let csvString = " , \n"
let csv = try! CSVReader(string: csvString, trimFields: true)
let records = AnyIterator(csv).map { $0 }
XCTAssertEqual(records.count, 1)
XCTAssertEqual(records[0], ["", ""])
}
func testTrimFields18() {
let csvString = " , \n "
let csv = try! CSVReader(string: csvString, trimFields: true)
let records = AnyIterator(csv).map { $0 }
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["", ""])
XCTAssertEqual(records[1], [""])
}
}

View File

@ -1,113 +0,0 @@
//
// UnicodeTests.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/10/18.
// Copyright © 2016 yaslab. All rights reserved.
//
import Foundation
import XCTest
@testable import CSV
class UnicodeTests: XCTestCase {
func testUTF8WithBOM() {
let csvString = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = String.Encoding.utf8
var mutableData = Data()
mutableData.append(contentsOf: UnicodeBOM.utf8)
mutableData.append(csvString.data(using: encoding)!)
let stream = InputStream(data: mutableData)
let csv = try! CSVReader(stream: stream, codecType: UTF8.self)
let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testUTF16WithNativeEndianBOM() {
let csvString = "abab,,cdcd,efef\r\nzxcv,😆asdf,\"qw\"\"er\","
let encoding = String.Encoding.utf16
var mutableData = Data()
mutableData.append(csvString.data(using: encoding)!)
let stream = InputStream(data: mutableData as Data)
let csv = try! CSVReader(stream: stream, codecType: UTF16.self, endian: .unknown)
let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "😆asdf", "qw\"er", ""])
}
func testUTF16WithBigEndianBOM() {
let csvString = "abab,,cdcd,efef\r\n😆zxcv,asdf,\"qw\"\"er\","
let encoding = String.Encoding.utf16BigEndian
var mutableData = Data()
mutableData.append(contentsOf: UnicodeBOM.utf16BE)
mutableData.append(csvString.data(using: encoding)!)
let stream = InputStream(data: mutableData as Data)
let csv = try! CSVReader(stream: stream, codecType: UTF16.self, endian: .big)
let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["😆zxcv", "asdf", "qw\"er", ""])
}
func testUTF16WithLittleEndianBOM() {
let csvString = "abab,,cdcd,efef\r\nzxcv😆,asdf,\"qw\"\"er\","
let encoding = String.Encoding.utf16LittleEndian
var mutableData = Data()
mutableData.append(contentsOf: UnicodeBOM.utf16LE)
mutableData.append(csvString.data(using: encoding)!)
let stream = InputStream(data: mutableData as Data)
let csv = try! CSVReader(stream: stream, codecType: UTF16.self, endian: .little)
let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv😆", "asdf", "qw\"er", ""])
}
func testUTF32WithNativeEndianBOM() {
let csvString = "😆abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = String.Encoding.utf32
var mutableData = Data()
mutableData.append(csvString.data(using: encoding)!)
let stream = InputStream(data: mutableData as Data)
let csv = try! CSVReader(stream: stream, codecType: UTF32.self, endian: .unknown)
let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["😆abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testUTF32WithBigEndianBOM() {
let csvString = "abab,,cd😆cd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = String.Encoding.utf32BigEndian
var mutableData = Data()
mutableData.append(contentsOf: UnicodeBOM.utf32BE)
mutableData.append(csvString.data(using: encoding)!)
let stream = InputStream(data: mutableData as Data)
let csv = try! CSVReader(stream: stream, codecType: UTF32.self, endian: .big)
let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cd😆cd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testUTF32WithLittleEndianBOM() {
let csvString = "abab,,cdcd,ef😆ef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = String.Encoding.utf32LittleEndian
var mutableData = Data()
mutableData.append(contentsOf: UnicodeBOM.utf32LE)
mutableData.append(csvString.data(using: encoding)!)
let stream = InputStream(data: mutableData as Data)
let csv = try! CSVReader(stream: stream, codecType: UTF32.self, endian: .little)
let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "ef😆ef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
private func getRecords(csv: CSVReader) -> [[String]] {
return csv.map { $0 }
// var records = [[String]]()
// try! csv.enumerateRows { (record, _, _) in
// records.append(record)
// }
// return records
}
}

View File

@ -1,106 +0,0 @@
//
// Version1Tests.swift
// CSV
//
// Created by Yasuhiro Hatta on 2017/06/18.
// Copyright © 2017 yaslab. All rights reserved.
//
import Foundation
import XCTest
import CSV
class Version1Tests: XCTestCase {
func testV1() {
let str = "a,b,c\n1,2,3"
let data8 = str.data(using: .utf8)!
let data16 = str.data(using: .utf16BigEndian)!
let data32 = str.data(using: .utf32BigEndian)!
let headerRow = ["a", "b", "c"]
let row = ["1", "2", "3"]
do {
let stream = InputStream(data: data8)
let csv = try CSVReader(stream: stream,
codecType: UTF8.self,
hasHeaderRow: true,
trimFields: false,
delimiter: ",")
XCTAssertEqual(csv.headerRow!, headerRow)
XCTAssertEqual(csv.next()!, row)
XCTAssertEqual(csv["a"], row[0])
} catch {
fatalError()
}
do {
let stream = InputStream(data: data16)
let csv = try CSVReader(stream: stream,
codecType: UTF16.self,
endian: .big,
hasHeaderRow: true,
trimFields: false,
delimiter: ",")
XCTAssertEqual(csv.headerRow!, headerRow)
XCTAssertEqual(csv.next()!, row)
XCTAssertEqual(csv["a"], row[0])
} catch {
fatalError()
}
do {
let stream = InputStream(data: data32)
let csv = try CSVReader(stream: stream,
codecType: UTF32.self,
endian: .big,
hasHeaderRow: true,
trimFields: false,
delimiter: ",")
XCTAssertEqual(csv.headerRow!, headerRow)
XCTAssertEqual(csv.next()!, row)
XCTAssertEqual(csv["a"], row[0])
} catch {
fatalError()
}
do {
let stream = InputStream(data: data8)
let csv = try CSVReader(stream: stream,
hasHeaderRow: true,
trimFields: false,
delimiter: ",")
XCTAssertEqual(csv.headerRow!, headerRow)
XCTAssertEqual(csv.next()!, row)
XCTAssertEqual(csv["a"], row[0])
} catch {
fatalError()
}
do {
let csv = try CSVReader(string: str,
hasHeaderRow: true,
trimFields: false,
delimiter: ",")
XCTAssertEqual(csv.headerRow!, headerRow)
XCTAssertEqual(csv.next()!, row)
XCTAssertEqual(csv["a"], row[0])
} catch {
fatalError()
}
_ = CSVError.cannotOpenFile
_ = CSVError.cannotReadFile
_ = CSVError.streamErrorHasOccurred(error: NSError(domain: "", code: 0, userInfo: nil))
_ = CSVError.cannotReadHeaderRow
_ = CSVError.stringEncodingMismatch
_ = CSVError.stringEndianMismatch
_ = Endian.big
_ = Endian.little
_ = Endian.unknown
}
}

View File

@ -1,196 +0,0 @@
#if !canImport(ObjectiveC)
import XCTest
extension BinaryReaderTests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__BinaryReaderTests = [
("testReadUInt16BEWithSmallBuffer", testReadUInt16BEWithSmallBuffer),
("testReadUInt16LEWithSmallBuffer", testReadUInt16LEWithSmallBuffer),
("testReadUInt32BEWithSmallBuffer", testReadUInt32BEWithSmallBuffer),
("testReadUInt32LEWithSmallBuffer", testReadUInt32LEWithSmallBuffer),
("testReadUInt8WithSmallBuffer", testReadUInt8WithSmallBuffer),
]
}
extension CSVReaderTests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__CSVReaderTests = [
("testCommaInQuotationMarks", testCommaInQuotationMarks),
("testCSVState1", testCSVState1),
("testDoubleQuoteBeforeLineBreak1", testDoubleQuoteBeforeLineBreak1),
("testDoubleQuoteBeforeLineBreak2", testDoubleQuoteBeforeLineBreak2),
("testEmptyField", testEmptyField),
("testEscapedQuotationMark1", testEscapedQuotationMark1),
("testEscapedQuotationMark2", testEscapedQuotationMark2),
("testHasHeaderRow1", testHasHeaderRow1),
("testHasHeaderRow2", testHasHeaderRow2),
("testHasHeaderRow3", testHasHeaderRow3),
("testHasHeaderRow4", testHasHeaderRow4),
("testLastLineIsEmpty", testLastLineIsEmpty),
("testLastLineIsWhiteSpace", testLastLineIsWhiteSpace),
("testMiddleLineIsEmpty", testMiddleLineIsEmpty),
("testOneLine", testOneLine),
("testSubscript1", testSubscript1),
("testSubscript2", testSubscript2),
("testSubscriptInt", testSubscriptInt),
("testToArray", testToArray),
("testTwoLines", testTwoLines),
]
}
extension CSVRowDecoderTests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__CSVRowDecoderTests = [
("testBoolDecodingStrategy_custom", testBoolDecodingStrategy_custom),
("testBoolDecodingStrategy_default", testBoolDecodingStrategy_default),
("testDataDecodingStrategy_base64", testDataDecodingStrategy_base64),
("testDataDecodingStrategy_custom", testDataDecodingStrategy_custom),
("testDateDecodingStrategy_custom", testDateDecodingStrategy_custom),
("testDateDecodingStrategy_deferredToDate", testDateDecodingStrategy_deferredToDate),
("testDateDecodingStrategy_formatted", testDateDecodingStrategy_formatted),
("testDateDecodingStrategy_iso8601", testDateDecodingStrategy_iso8601),
("testDateDecodingStrategy_millisecondsSince1970", testDateDecodingStrategy_millisecondsSince1970),
("testDateDecodingStrategy_secondsSince1970", testDateDecodingStrategy_secondsSince1970),
("testDecodeFloat", testDecodeFloat),
("testDecodeInteger", testDecodeInteger),
("testFoundationDecoding", testFoundationDecoding),
("testIntCodingKey", testIntCodingKey),
("testIntCodingKeyWhileIgnoringHeaders", testIntCodingKeyWhileIgnoringHeaders),
("testNoHeader", testNoHeader),
("testNumberOfFieldsIsSmall", testNumberOfFieldsIsSmall),
("testStringCodingKey", testStringCodingKey),
("testTypeInvalidDateFormat", testTypeInvalidDateFormat),
("testTypeMismatch", testTypeMismatch),
("testUnsupportedDecodableField", testUnsupportedDecodableField),
]
}
extension CSVWriterTests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__CSVWriterTests = [
("testDelimiter", testDelimiter),
("testEscapeQuote", testEscapeQuote),
("testEscapeQuoteAutomatically", testEscapeQuoteAutomatically),
("testMultipleFieldMultipleRecord", testMultipleFieldMultipleRecord),
("testMultipleFieldSingleRecord", testMultipleFieldSingleRecord),
("testNewline", testNewline),
("testQuoted", testQuoted),
("testQuotedNewline", testQuotedNewline),
("testReadme", testReadme),
("testSingleFieldMultipleRecord", testSingleFieldMultipleRecord),
("testSingleFieldSingleRecord", testSingleFieldSingleRecord),
("testUTF16BE", testUTF16BE),
("testUTF16LE", testUTF16LE),
("testUTF32BE", testUTF32BE),
("testUTF32LE", testUTF32LE),
("testValueContainsComma", testValueContainsComma),
]
}
extension LineBreakTests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__LineBreakTests = [
("testCRLF", testCRLF),
("testLastCR", testLastCR),
("testLastCRLF", testLastCRLF),
("testLastLF", testLastLF),
("testLF", testLF),
("testLFInQuotationMarks", testLFInQuotationMarks),
("testLineBreakCR", testLineBreakCR),
("testLineBreakCRCR", testLineBreakCRCR),
("testLineBreakCRLF", testLineBreakCRLF),
("testLineBreakCRLFCRLF", testLineBreakCRLFCRLF),
("testLineBreakLF", testLineBreakLF),
("testLineBreakLFLF", testLineBreakLFLF),
]
}
extension ReadmeTests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__ReadmeTests = [
("testFromCSVString", testFromCSVString),
("testFromFile", testFromFile),
("testGetTheFieldValueUsingKey", testGetTheFieldValueUsingKey),
("testGettingTheHeaderRow", testGettingTheHeaderRow),
("testProvideTheCharacterEncoding", testProvideTheCharacterEncoding),
("testWriteToFile", testWriteToFile),
("testWriteToMemory", testWriteToMemory),
]
}
extension TrimFieldsTests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__TrimFieldsTests = [
("testTrimFields1", testTrimFields1),
("testTrimFields10", testTrimFields10),
("testTrimFields11", testTrimFields11),
("testTrimFields12", testTrimFields12),
("testTrimFields13", testTrimFields13),
("testTrimFields14", testTrimFields14),
("testTrimFields15", testTrimFields15),
("testTrimFields16", testTrimFields16),
("testTrimFields17", testTrimFields17),
("testTrimFields18", testTrimFields18),
("testTrimFields2", testTrimFields2),
("testTrimFields3", testTrimFields3),
("testTrimFields4", testTrimFields4),
("testTrimFields5", testTrimFields5),
("testTrimFields6", testTrimFields6),
("testTrimFields7", testTrimFields7),
("testTrimFields8", testTrimFields8),
("testTrimFields9", testTrimFields9),
]
}
extension UnicodeTests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__UnicodeTests = [
("testUTF16WithBigEndianBOM", testUTF16WithBigEndianBOM),
("testUTF16WithLittleEndianBOM", testUTF16WithLittleEndianBOM),
("testUTF16WithNativeEndianBOM", testUTF16WithNativeEndianBOM),
("testUTF32WithBigEndianBOM", testUTF32WithBigEndianBOM),
("testUTF32WithLittleEndianBOM", testUTF32WithLittleEndianBOM),
("testUTF32WithNativeEndianBOM", testUTF32WithNativeEndianBOM),
("testUTF8WithBOM", testUTF8WithBOM),
]
}
extension Version1Tests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__Version1Tests = [
("testV1", testV1),
]
}
public func __allTests() -> [XCTestCaseEntry] {
return [
testCase(BinaryReaderTests.__allTests__BinaryReaderTests),
testCase(CSVReaderTests.__allTests__CSVReaderTests),
testCase(CSVRowDecoderTests.__allTests__CSVRowDecoderTests),
testCase(CSVWriterTests.__allTests__CSVWriterTests),
testCase(LineBreakTests.__allTests__LineBreakTests),
testCase(ReadmeTests.__allTests__ReadmeTests),
testCase(TrimFieldsTests.__allTests__TrimFieldsTests),
testCase(UnicodeTests.__allTests__UnicodeTests),
testCase(Version1Tests.__allTests__Version1Tests),
]
}
#endif

View File

@ -1,8 +1,14 @@
//
// LinuxMain.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/11.
//
//
import XCTest
@testable import CSVTestSuite
import CSVTests
var tests = [XCTestCaseEntry]()
tests += CSVTests.__allTests()
XCTMain(tests)
XCTMain([
testCase(CSVReaderTests.allTests),
])