Compare commits

...

241 Commits

Author SHA1 Message Date
Yasuhiro Hatta 81d2874c51
Merge pull request #111 from yaslab/release-2.4.3
Release 2.4.3
2020-03-14 18:12:01 +09:00
Yasuhiro Hatta 8a3b2328a5 Release 2.4.3 2020-03-14 18:07:16 +09:00
Yasuhiro Hatta 708202871d
Merge pull request #101 from gallgall/master
Add nil decoding strategy
2020-01-16 17:09:39 +09:00
Yasuhiro Hatta 2fd6693009
Merge pull request #103 from vipt/master
Automatically quote values that contain newlines and delimiters
2020-01-16 17:07:40 +09:00
motoki f8a90ce8bc Automatically quote values that contain newlines and delimiters 2020-01-11 12:26:45 +09:00
Hai Nguyen Minh ee138a8572 Add nil decoding strategy 2019-11-14 10:47:59 +07:00
Yasuhiro Hatta e8e82ac6fb
Merge pull request #97 from yaslab/readme
Update README.md
2019-07-14 15:13:47 +09:00
Yasuhiro Hatta f68c752e4a swift test --generate-linuxmain 2019-07-14 15:01:14 +09:00
Yasuhiro Hatta b12e3df560 Update README.md 2019-07-14 14:47:41 +09:00
Yasuhiro Hatta 67c5209ae6
Merge pull request #96 from yaslab/release-2.4.2
Release 2.4.2
2019-07-13 15:20:17 +09:00
Yasuhiro Hatta 1a2aebf797
Merge pull request #95 from yaslab/swiftlint
Update .swiftlint.yml
2019-07-13 15:17:45 +09:00
Yasuhiro Hatta 58fee7bcab Update podspec 2019-07-13 15:17:25 +09:00
Yasuhiro Hatta 2797e65776 Release 2.4.2 2019-07-13 15:12:45 +09:00
Yasuhiro Hatta 022af3f3e1 Update .swiftlint.yml 2019-07-13 15:08:41 +09:00
Yasuhiro Hatta b95c94934f
Merge pull request #93 from yaslab/add-more-unit-tests
Add more unit tests
2019-06-29 21:33:36 +09:00
Yasuhiro Hatta 7ea1f25307 Fix compiler warning 2019-06-29 21:13:14 +09:00
Yasuhiro Hatta 0f9d4bfd27 Generate LinuxMain.swift using `swift test --generate-linuxmain` 2019-06-29 21:11:46 +09:00
Yasuhiro Hatta b11cfb960f Fix compiler warning 2019-06-29 21:03:08 +09:00
Yasuhiro Hatta 126841fae4 Add more unit tests 2019-06-29 21:02:06 +09:00
Yasuhiro Hatta ee50dd334d
Merge pull request #92 from yaslab/fix/83
Fix a crash that occurs when the number of fields is small
2019-06-29 18:11:22 +09:00
Yasuhiro Hatta 266f27e047 Fix a crash that occurs when the number of fields is small 2019-06-29 18:00:17 +09:00
Yasuhiro Hatta b5514ec6f3
Merge pull request #91 from yaslab/release-2.4.1
Release 2.4.1
2019-06-22 21:25:52 +09:00
Yasuhiro Hatta 8d3e55cfcb Release 2.4.1 2019-06-22 21:20:57 +09:00
Yasuhiro Hatta f99b3f4ba8
Merge pull request #90 from yaslab/legacy
Mark `CSV` as deprecated
2019-06-22 21:16:22 +09:00
Yasuhiro Hatta eb004b3773 Format source code 2019-06-22 21:12:50 +09:00
Yasuhiro Hatta a22693a7d4 Mark `CSV` as deprecated 2019-06-22 21:11:19 +09:00
Yasuhiro Hatta 849e82c73c
Merge pull request #89 from mxcl/quote-commas
Automatically quote values that contain commas
2019-06-20 23:31:12 +09:00
Max Howell 33dbff0577
Automatically quote values that contain commas 2019-06-19 10:03:49 -04:00
Yasuhiro Hatta af907b46f7
Merge pull request #87 from yaslab/release-2.4.0
Release 2.4.0
2019-05-11 11:48:03 +09:00
Yasuhiro Hatta 0de3fcdb9e Release 2.4.0 2019-05-11 11:39:41 +09:00
Yasuhiro Hatta 4da0ec833e
Merge pull request #86 from yaslab/swift-5
Update to Swift 5
2019-05-11 11:35:49 +09:00
Yasuhiro Hatta 9eef621761 Update to Swift 5 2019-05-11 11:32:16 +09:00
Yasuhiro Hatta 644f0a1cbd
Merge pull request #84 from UberJason/swift5-support
Update project to Swift 5 and latest Xcode 10.2 settings
2019-05-11 10:46:25 +09:00
Jason Ji 6e1db1513d Update project to Swift 5 and latest Xcode 10.2 settings 2019-04-05 20:40:34 -04:00
Yasuhiro Hatta c88aca7850
Merge pull request #78 from yaslab/release-2.3.1
Release 2.3.1
2018-12-06 23:38:05 +09:00
Yasuhiro Hatta dbf6697a9f Release 2.3.1 2018-12-06 23:33:18 +09:00
Yasuhiro Hatta dd0effcc80
Merge pull request #77 from yaslab/feature/bool-decoding-strategy
Add BoolDecodingStrategy
2018-12-06 23:28:38 +09:00
Yasuhiro Hatta 38ec4535ae Add BoolDecodingStrategy 2018-12-06 00:36:54 +09:00
Yasuhiro Hatta 521b6c15da
Merge pull request #75 from yaslab/release-2.3.0
Release 2.3.0
2018-12-01 12:38:15 +09:00
Yasuhiro Hatta 2df12cddca Release 2.3.0 2018-12-01 12:32:55 +09:00
Yasuhiro Hatta c18ee80f02
Merge pull request #74 from yaslab/refactoring
Clean up the source code
2018-12-01 11:59:24 +09:00
Yasuhiro Hatta 7658b390fd Add more CSVRowDecoder tests 2018-12-01 11:25:50 +09:00
Yasuhiro Hatta 48f051fb7d Refactored CSVRowDecoder 2018-12-01 09:47:39 +09:00
Yasuhiro Hatta 7d10f1f7f6 Refactored CSVRowDecoderTests 2018-11-29 00:58:57 +09:00
Yasuhiro Hatta 61d2ce8a00 Update README.md 2018-11-29 00:58:34 +09:00
Yasuhiro Hatta 2af710083e Update README.md 2018-11-29 00:53:20 +09:00
Yasuhiro Hatta 4dcc07721b Refactored CSVRowDecoderTests 2018-11-29 00:44:59 +09:00
Yasuhiro Hatta bf2e166146 Refactored CSVRowDecoder 2018-11-28 23:44:22 +09:00
Yasuhiro Hatta fdd4e34621 Refactored CSVRowDecoder 2018-11-26 01:13:38 +09:00
Yasuhiro Hatta 3990cb04f4 Refactored CSVRowDecoder 2018-11-26 00:52:19 +09:00
Yasuhiro Hatta 5a86d95312 Rename 2018-11-26 00:35:18 +09:00
Yasuhiro Hatta f96fb1c632
Merge pull request #73 from yaslab/decoding-strategy
Implement decoding strategy
2018-11-26 00:28:53 +09:00
Yasuhiro Hatta 8158330910 Remove whitespace 2018-11-26 00:16:34 +09:00
Yasuhiro Hatta 9b35f60a09 Implement decoding strategy 2018-11-26 00:00:59 +09:00
Yasuhiro Hatta 13f9e75ef2
Merge pull request #72 from sstadelman/master
Added support for decoding with  Int-based CodingKey
2018-11-25 19:09:28 +09:00
i826181 aebee51287 refactored decodable test struct 2018-11-24 21:44:13 -08:00
i826181 fb2e641345 added test case for ignoring header with int codingkey 2018-11-24 21:01:50 -08:00
i826181 1e63a5438d Added support for decoding with Int-based CodingKey 2018-11-24 18:03:50 -08:00
Yasuhiro Hatta ff764ff8a9
Merge pull request #68 from yaslab/fix/decoder
Fix build error that kCFBooleanTrue / False can not be resolved on linux
2018-11-23 23:07:06 +09:00
Yasuhiro Hatta 9352ed330c Make all the tests successful 2018-11-23 22:56:08 +09:00
Yasuhiro Hatta 798e696202 Add nil check 2018-11-23 11:41:26 +09:00
Yasuhiro Hatta 02ae6c51f1 Fix build error that kCFBooleanTrue / False can not be resolved on linux 2018-11-23 11:31:42 +09:00
Yasuhiro Hatta 2218559821
Merge pull request #66 from yaslab/fix-build
Fix build time error by “File Line Length Violation” rule
2018-11-17 16:20:19 +09:00
Yasuhiro Hatta 25768e174a Fix build time error by “File Line Length Violation” rule 2018-11-17 16:13:57 +09:00
Yasuhiro Hatta d124b1a99a
Merge pull request #65 from yaslab/speed-up
[Speed] Add buffer to BinaryReader
2018-11-17 15:55:43 +09:00
Yasuhiro Hatta 1e83c6e3b9 Merge branch 'master' into speed-up
# Conflicts:
#	CSV.xcodeproj/project.pbxproj
2018-11-17 15:49:44 +09:00
Yasuhiro Hatta 329bf23405
Merge pull request #61 from Adorkable-forkable/feature/Decodable
Decodable support
2018-11-17 15:30:28 +09:00
Yasuhiro Hatta b01cbb358d Update _count and _position before break 2018-11-15 23:03:35 +09:00
Yasuhiro Hatta 40a8f59f88 Use `|` instead of `+` 2018-11-15 22:48:26 +09:00
Yasuhiro Hatta e12c86f170 Avoid BOM 2018-11-15 22:41:20 +09:00
Yasuhiro Hatta 826ce290a2 Update to Xcode 10.1 2018-11-15 22:26:39 +09:00
Yasuhiro Hatta 66945c0891 Add BinaryReader Tests 2018-11-15 22:24:18 +09:00
Yasuhiro Hatta 028bd2f5a8 [Speed] Add buffer to BinaryReader 2018-11-15 02:07:59 +09:00
Yasuhiro Hatta 6a189246ba [Speed] String.UnicodeScalarView#removeAll is slow 2018-11-13 00:48:11 +09:00
Ian G 0669601280 Support for SingleValueDecodingContainer, enum processing 2018-09-11 17:05:52 -04:00
Ian G 68a7e0469a Reorganized and elaborated tests 2018-09-11 15:30:32 -04:00
Ian G 15540460ab Push Coding Path for context 2018-09-11 14:28:22 -04:00
Ian G cce830e35c Automatic decoding of Date 2018-09-11 13:49:12 -04:00
Ian G 9739fc74c6 Decodable support 2018-09-11 11:32:11 -04:00
Yasuhiro Hatta 487816c0d1
Merge pull request #58 from yaslab/linux-tests
[LinuxTests] Add missing Linux tests
2018-04-22 12:16:36 +09:00
Yasuhiro Hatta 5556448ccc [LinuxTests] Add missing Linux tests 2018-04-22 12:08:19 +09:00
Yasuhiro Hatta 032be4276e
Merge pull request #57 from yaslab/release-2.2.1
Bump version 2.2.1
2018-04-22 11:54:26 +09:00
Yasuhiro Hatta 22fd4ee97c Release 2.2.1 2018-04-22 11:52:01 +09:00
Yasuhiro Hatta 1c40a3b1ec
Merge pull request #56 from yaslab/issue-52
[CSVWriter] csv.write not following RFC4180
2018-04-22 11:47:06 +09:00
Yasuhiro Hatta f6690b15a4 [CSVWriter] Escape quote automatically #52 2018-04-22 11:38:36 +09:00
Yasuhiro Hatta 749e7a5648 [CSVWriterTests] Escape quote automatically #52 2018-04-22 11:38:09 +09:00
Yasuhiro Hatta 59dc282e80
Merge pull request #49 from codetriage-readme-bot/codetriage-badge
Add CodeTriage badge to yaslab/csv.swift
2018-04-22 11:05:49 +09:00
Yasuhiro Hatta 261a9a06c1
Merge pull request #55 from yaslab/fix-target
Fix error: could not find target(s): CSV
2018-04-21 21:22:27 +09:00
Yasuhiro Hatta c1c78d75ca Update podspec 2018-04-21 21:18:19 +09:00
Yasuhiro Hatta 7b20172a9c Fix error: could not find target(s): CSV 2018-04-21 21:16:08 +09:00
Yasuhiro Hatta d47c168117
Merge pull request #54 from yaslab/release-2.2.0
Bump version 2.2.0
2018-04-21 20:55:21 +09:00
Yasuhiro Hatta 3e51573eb7 Release 2.2.0 2018-04-20 16:25:39 +09:00
Yasuhiro Hatta 5d6e01ff90 Update Package.swift to swift 4.0 2018-04-20 16:24:34 +09:00
Yasuhiro Hatta 2d89f13524 Update tvOS, watchOS and macOS projects to swift 4.0 2018-04-20 16:15:38 +09:00
Yasuhiro Hatta 244c2aacd2
Merge pull request #53 from mbarclay/feature/xcode-9.3-swift-4.0-updates
Xcode 9.3 and Swift 4.0 Updates
2018-04-20 12:18:15 +09:00
Malcolm Barclay 6e01e88697 Xcode 9.3 and Swift 4.0 Updates 2018-04-19 18:27:13 +01:00
codetriage-readme-bot 9ecef44708 Add CodeTriage badge to yaslab/csv.swift
Adds a badge showing the number of people helping this repo on CodeTriage.

[![Open Source Helpers](https://www.codetriage.com/yaslab/csv.swift/badges/users.svg)](https://www.codetriage.com/yaslab/csv.swift)

## What is CodeTriage?

CodeTriage is an Open Source app that is designed to make contributing to Open Source projects easier. It works by sending subscribers a few open issues in their inbox. If subscribers get busy, there is an algorithm that backs off issue load so they do not get overwhelmed

[Read more about the CodeTriage project](https://www.codetriage.com/what).

## Why am I getting this PR?

Your project was picked by the human, @schneems. They selected it from the projects submitted to https://www.codetriage.com and hand edited the PR. How did your project get added to [CodeTriage](https://www.codetriage.com/what)? Roughly 6 months ago, [thejayhaykid](https://github.com/thejayhaykid) added this project to CodeTriage in order to start contributing. Since then, 3 people have subscribed to help this repo.

## What does adding a badge accomplish?

Adding a badge invites people to help contribute to your project. It also lets developers know that others are invested in the longterm success and maintainability of the project.

You can see an example of a CodeTriage badge on these popular OSS READMEs:

- [![](https://www.codetriage.com/rails/rails/badges/users.svg)](https://www.codetriage.com/rails/rails) https://github.com/rails/rails
- [![](https://www.codetriage.com/crystal-lang/crystal/badges/users.svg)](https://www.codetriage.com/crystal-lang/crystal) https://github.com/crystal-lang/crystal

## Have a question or comment?

While I am a bot, this PR was manually reviewed and monitored by a human - @schneems. My job is writing commit messages and handling PR logistics.

If you have any questions, you can reply back to this PR and they will be answered by @schneems. If you do not want a badge right now, no worries, close the PR, you will not hear from me again.

Thanks for making your project Open Source! Any feedback is greatly appreciated.
2018-02-10 08:44:28 -06:00
Yasuhiro Hatta a2a9e3f6e6 Merge pull request #39 from yaslab/readme
Update README.md
2017-09-23 18:40:17 +09:00
Yasuhiro Hatta 8e2319ba1d Update README.md 2017-09-23 18:39:05 +09:00
Yasuhiro Hatta cfa034a96c Update README.md 2017-09-23 18:33:44 +09:00
Yasuhiro Hatta 17b079f2d5 Merge pull request #38 from yaslab/swift4
Support for Swift 4
2017-09-23 18:30:15 +09:00
Yasuhiro Hatta 6cf6ab0ae9 Change Swift version to 3.2 2017-09-23 18:21:18 +09:00
Yasuhiro Hatta f1aa9b4016 Change Swift version to 3.2 2017-09-23 18:16:54 +09:00
Yasuhiro Hatta b8e1285b6f Release 2.1.0 2017-09-23 18:15:36 +09:00
Yasuhiro Hatta 4c4a5202fa Move the global public variable to be a member of the class 2017-09-23 18:01:10 +09:00
Yasuhiro Hatta e268fa3f3a Fix compiler warning 2017-09-23 17:49:36 +09:00
Yasuhiro Hatta 9f0cbddbfc Delete SWIFT_SWIFT3_OBJC_INFERENCE (Use default) 2017-09-23 17:48:29 +09:00
Yasuhiro Hatta 54a9d94ae4 Update to Xcode recommended settings 2017-09-23 17:44:11 +09:00
Yasuhiro Hatta 2410820dc4 Update .xcodeproj to Swift 4 2017-09-23 17:43:29 +09:00
Yasuhiro Hatta a3e770943d Merge pull request #37 from pefaymon/patch-1
Made default parameter values public
2017-09-23 17:37:47 +09:00
Peter Faymonville c318c8414d Made default parameter values public
Swift 4 compatibility
2017-09-21 17:44:29 +02:00
Yasuhiro Hatta f534685017 Merge pull request #34 from yaslab/readme
Update README.md
2017-07-17 15:52:09 +09:00
Yasuhiro Hatta f24b0674c2 Merge pull request #33 from yaslab/rename-macos
Rename OSX to macOS
2017-07-17 15:51:56 +09:00
Yasuhiro Hatta ce44b39fa5 Update README.md 2017-07-17 15:40:32 +09:00
Yasuhiro Hatta 69fe1b65c7 Rename OSX to macOS 2017-07-17 15:34:25 +09:00
Yasuhiro Hatta 0030f5dffd Rename OSX to macOS 2017-07-17 15:27:25 +09:00
Yasuhiro Hatta 21ba14ace9 Merge pull request #30 from yaslab/update-readme
Update README.md
2017-07-09 15:19:19 +09:00
Yasuhiro Hatta c14ae1dc92 Update README.md 2017-07-09 15:14:51 +09:00
Yasuhiro Hatta 17964baee5 Merge pull request #29 from yaslab/v201
Bump version 2.0.1
2017-07-09 14:52:09 +09:00
Yasuhiro Hatta c1fb896564 Bump version 2.0.1 2017-07-09 14:50:38 +09:00
Yasuhiro Hatta 1f4719e8e2 Merge pull request #28 from yaslab/podspec
Update podspec summary
2017-07-09 14:42:53 +09:00
Yasuhiro Hatta be82f7144c Update podspec summary 2017-07-09 14:38:37 +09:00
Yasuhiro Hatta 5ff2177938 Update comment 2017-07-09 14:38:09 +09:00
Yasuhiro Hatta 88d88c6fae Merge pull request #27 from yaslab/codecov
Add codecov badge to README.md
2017-07-09 14:35:23 +09:00
Yasuhiro Hatta 34451b9823 [codecov] Add codecov badge to README.md 2017-07-09 14:32:27 +09:00
Yasuhiro Hatta 000c011aa9 [codecov] Update .travis.yml 2017-07-09 14:29:10 +09:00
Yasuhiro Hatta 5c9bbc0db7 [codecov] Update xcscheme 2017-07-09 14:28:56 +09:00
Yasuhiro Hatta 1ca5d1a558 Merge pull request #21 from yaslab/develop
Version 2.0
2017-06-19 02:45:58 +09:00
Yasuhiro Hatta 3639a75c33 Add enum Newline for Writer 2017-06-19 02:42:35 +09:00
Yasuhiro Hatta 015caedd64 Update README.md 2017-06-19 02:28:42 +09:00
Yasuhiro Hatta 0ef7b0eb0e Bump version 2.0.0 2017-06-19 02:22:53 +09:00
Yasuhiro Hatta 7ad80457ab Fix test for Linux 2017-06-18 17:53:37 +09:00
Yasuhiro Hatta cab93830fe Fix file misplacement 2017-06-18 17:49:45 +09:00
Yasuhiro Hatta c3402699e7 Merge pull request #26 from yaslab/compatibility
Keep compatibility with version 1
2017-06-18 16:23:11 +09:00
Yasuhiro Hatta 2a284b6d3d Keep compatibility with version 1 2017-06-18 15:50:31 +09:00
Yasuhiro Hatta 71ab28eadd Merge pull request #25 from yaslab/rename-csvreader
Rename CSV to CSVReader
2017-06-01 02:22:10 +09:00
Yasuhiro Hatta 7d56f466a9 Rename CSV to CSVReader 2017-05-29 01:33:24 +09:00
Yasuhiro Hatta 03c2d8bce3 Merge pull request #24 from yaslab/writer
Add `CSVWriter` class
2017-05-28 18:26:56 +09:00
Yasuhiro Hatta d9e0b1d369 Add more CSVWriter tests 2017-05-28 18:23:45 +09:00
Yasuhiro Hatta b0ac142fde Fix CSVWriterTests for Linux 2017-05-28 15:27:03 +09:00
Yasuhiro Hatta 683e286ac7 chmod -x 2017-05-28 15:17:39 +09:00
Yasuhiro Hatta d9213a7c62 chmod -x 2017-05-28 15:16:19 +09:00
Yasuhiro Hatta cf430d4ed2 Add Linux Tests 2017-05-28 14:50:59 +09:00
Yasuhiro Hatta eb38710590 Implement error handling 2017-05-28 14:27:11 +09:00
Yasuhiro Hatta 1d72634a03 Update .travis.yml 2017-05-28 13:35:40 +09:00
Yasuhiro Hatta f46887bdbb Add more CSVWriter tests 2017-05-28 12:59:19 +09:00
Yasuhiro Hatta 1918e5163d Correct file misplacement 2017-05-28 12:58:38 +09:00
Yasuhiro Hatta 376640007e Use UnicodeScalar insted of Unicode.Scalar 2017-05-28 12:54:47 +09:00
Yasuhiro Hatta 3bf2eab076 Add CSVWriter class 2017-05-28 12:20:29 +09:00
Yasuhiro Hatta 7b9caaf9a8 Changed to use character literal 2017-05-27 22:27:53 +09:00
Yasuhiro Hatta 2f7accff1a Fix swiftlint warning 2016-12-23 16:58:14 +09:00
Yasuhiro Hatta 13c29f98ed Merge branch 'master' into develop
# Conflicts:
#	Tests/CSVTests/CSVTests.swift
#	Tests/CSVTests/ReadmeTests.swift
2016-12-23 16:52:27 +09:00
Yasuhiro Hatta e7405829b1 Merge pull request #20 from yaslab/issue-19
Bump version 1.1.2
2016-11-29 22:09:52 +09:00
Yasuhiro Hatta 117640b9e9 Bump version 1.1.2 2016-11-29 21:43:46 +09:00
Yasuhiro Hatta d65943c6d0 Merge pull request #18 from choefele/master
Add support for Linux-based builds
2016-11-29 21:32:51 +09:00
Claus Höfele 9a061c28c3 Hook up unit tests for Linux-based builds 2016-11-28 22:18:40 +01:00
Claus Höfele d3d9fab63f Import Foundation
Required on Linux for Data and InputStream
2016-11-28 22:04:27 +01:00
Claus Höfele 5568da5328 Use stdlib byte swapping functionality
Byte swapping functionality in stdlib works on both macOS and Linux (in contrast to CFSwapXX utilities which are only available on macOS as part of CoreFoundation)
2016-11-28 21:58:09 +01:00
Yasuhiro Hatta aa5fd6ac03 Replace “var” with “let” 2016-11-16 01:49:25 +09:00
Yasuhiro Hatta 7b3d6e73cd Merge branch 'master' into develop
# Conflicts:
#	CSV.xcodeproj/project.pbxproj
2016-11-16 01:47:45 +09:00
Yasuhiro Hatta 853233e4a7 Fix the misplacement of file 2016-11-16 01:23:32 +09:00
Yasuhiro Hatta 6428660c99 Update podspec 2016-11-14 00:51:53 +09:00
Yasuhiro Hatta 0971f82956 Update project.pbxproj 2016-11-14 00:42:43 +09:00
Yasuhiro Hatta 9dccfdf92b Merge pull request #17 from lightsprint09/master
Updates PackageManager structure to fix error
2016-11-14 00:35:11 +09:00
Lukas Schmidt 2b7a25a378 Updates Package structure to fix error
error: the module at Tests/CSV has an invalid name ('CSV'): the name of
a test module has no ‘Tests’ suffix
fix: rename the module at ‘Tests/CSV’ to have a ‘Tests’ suffix
2016-11-13 14:11:47 +01:00
Yasuhiro Hatta 24a63ffc49 Merge pull request #16 from yaslab/hotfix/circular-reference
Fix circular reference
2016-11-05 17:23:35 +09:00
Yasuhiro Hatta cc2437e177 Fix circular reference 2016-11-05 17:22:29 +09:00
Yasuhiro Hatta b6733645a7 Merge pull request #15 from yaslab/feature/speed-up
Speed up
2016-11-04 21:38:08 +09:00
Yasuhiro Hatta 485738a95c Use `malloc` / `free` instead of `Array` 2016-11-04 20:05:40 +09:00
Yasuhiro Hatta c6cdbd1bd8 Use `String.UnicodeScalarView` instead of `String` 2016-11-04 19:56:59 +09:00
Yasuhiro Hatta 143a9b9740 Merge pull request #14 from yaslab/hotfix/subscript
Fix subscript
2016-11-04 19:25:09 +09:00
Yasuhiro Hatta df1f384079 Merge pull request #12 from yaslab/feature/error-handling
Error handling
2016-11-04 19:19:45 +09:00
Yasuhiro Hatta f93b83c26b Merge pull request #11 from yaslab/feature/new-row-struct
Enumerate the Row struct instead of a [String]
2016-11-04 19:19:07 +09:00
Yasuhiro Hatta 73e8b6ec01 Merge pull request #13 from yaslab/xcode81
Update to Xcode 8.1
2016-10-30 17:46:06 +09:00
Yasuhiro Hatta 8fcb59b43c Update to Xcode 8.1 2016-10-30 17:41:10 +09:00
Yasuhiro Hatta bdefb44a91 Fix subscript 2016-10-30 17:38:25 +09:00
Yasuhiro Hatta f0f0ea84de Update README.md 2016-10-29 11:27:08 +09:00
Yasuhiro Hatta 597272db9b Error handling #10 2016-10-24 01:22:23 +09:00
Yasuhiro Hatta 28c54df853 Code cleanup 2016-10-23 23:32:09 +09:00
Yasuhiro Hatta be8d1fda41 Add more whitespace tests 2016-10-23 02:25:48 +09:00
Yasuhiro Hatta 0b0fcd8cbb CSV subscript to be unavailable 2016-10-23 02:24:09 +09:00
Yasuhiro Hatta 40e34fc990 Replace magic number with variable 2016-10-23 02:22:07 +09:00
Yasuhiro Hatta ac6d663703 Update comment 2016-10-23 02:20:24 +09:00
Yasuhiro Hatta fde92925fc Merge branch 'master' into feature/new-row-struct
# Conflicts:
#	Sources/BinaryReader.swift
2016-10-23 01:08:04 +09:00
Yasuhiro Hatta 3834bbbb4f Run swiftlint autocorrect 2016-10-23 01:06:26 +09:00
Yasuhiro Hatta 345264273c Update .swiftlint.yml 2016-10-23 00:47:25 +09:00
Yasuhiro Hatta 3d502204f6 Merge pull request #9 from yaslab/code-cleanup
Code cleanup
2016-10-23 00:25:06 +09:00
Yasuhiro Hatta 3bd51605e7 Add .swiftlint.yml 2016-10-23 00:22:04 +09:00
Yasuhiro Hatta 44b4857396 Add `struct CSV.Row` 2016-10-23 00:02:31 +09:00
Yasuhiro Hatta f1ef6a7270 Update comments 2016-10-22 23:35:09 +09:00
Yasuhiro Hatta 479913f0f0 Test code cleanup 2016-10-18 00:58:40 +09:00
Yasuhiro Hatta acc4be2a35 Code cleanup 2016-10-18 00:34:12 +09:00
Yasuhiro Hatta 078c5be1c6 Merge pull request #8 from yaslab/feature/trim-fields
Trim each field
2016-10-17 00:37:26 +09:00
Yasuhiro Hatta 406c4032a5 Update whitespace test 2016-10-17 00:28:28 +09:00
Yasuhiro Hatta 22c582b14c Update README.md 2016-10-17 00:21:37 +09:00
Yasuhiro Hatta 0715a1db99 Bump version 1.1.0 2016-10-17 00:19:11 +09:00
Yasuhiro Hatta 4f29117767 Add test 2016-10-16 12:42:43 +09:00
Yasuhiro Hatta 8ad3238b16 Code refactoring 2016-10-16 12:42:33 +09:00
Yasuhiro Hatta 19e3ee98fa Implement function to trim the whitespaces 2016-10-16 11:52:16 +09:00
Yasuhiro Hatta 1ca77e6ae7 Add trim field tests 2016-10-16 11:37:01 +09:00
Yasuhiro Hatta b2658d4d04 [WIP] Trim each field 2016-10-16 10:38:27 +09:00
Yasuhiro Hatta 1c2961abff Update README.md 2016-09-25 02:15:39 +09:00
Yasuhiro Hatta f136093918 Add .swift-version 2016-09-25 02:06:44 +09:00
Yasuhiro Hatta cdeb78d3c0 Merge pull request #6 from yaslab/swift-3.0
Swift 3.0 support
2016-09-25 01:32:58 +09:00
Yasuhiro Hatta 96ddb0d017 Bump version 1.0.0 2016-09-25 01:30:40 +09:00
Yasuhiro Hatta 5e84f5e8d4 Update .travis.yml 2016-08-21 18:52:04 +09:00
Yasuhiro Hatta e010536e1e Swift 3.0 support #2 2016-08-21 18:48:17 +09:00
Yasuhiro Hatta 4c9bb24cb4 Swift 2.3 support #5 2016-08-21 12:43:24 +09:00
Yasuhiro Hatta 0acd6ddd20 Fix compiler warning 2016-08-21 11:32:27 +09:00
Yasuhiro Hatta 5c3228e218 Update README.md 2016-08-21 11:21:49 +09:00
Yasuhiro Hatta fe12a10546 Update podspec 2016-08-21 11:21:32 +09:00
Yasuhiro Hatta 7cd1d968dc Merge pull request #4 from yaslab/swift-2.2 2016-08-21 10:59:55 +09:00
Yasuhiro Hatta 445882ac94 Apply the UpperCamelCase to enums 2016-07-23 13:25:39 +09:00
Yasuhiro Hatta 2703bb9385 Version 0.3.0 2016-07-23 13:06:03 +09:00
Yasuhiro Hatta 85e1ece74c Implement error handling 2016-07-20 01:20:09 +09:00
Yasuhiro Hatta 0dfc025b79 Clean up the code 2016-07-20 01:17:27 +09:00
Yasuhiro Hatta d1f55063e3 Update .xcodeproj 2016-07-11 22:18:34 +09:00
Yasuhiro Hatta b0f8c83698 Update README.md 2016-06-26 02:48:11 +09:00
Yasuhiro Hatta 29d0f2b091 Use Swift built-in Unicode Codecs 2016-06-26 02:35:13 +09:00
Yasuhiro Hatta 4063a440e5 Swift 3.0 Preview 2 2016-06-25 18:02:37 +09:00
Yasuhiro Hatta 26b4bd153a Add CSV.init with UnicodeCodec 2016-06-25 14:47:48 +09:00
Yasuhiro Hatta 0718eab0bb Swift 3 support 2016-06-23 02:49:54 +09:00
Yasuhiro Hatta 90d9ca16a3 Rename CSV(path: ...) with CSV(fileAtPath: ...) 2016-06-23 01:06:50 +09:00
Yasuhiro Hatta ccadfd499e Change 'UnicodeIterator' to 'UTFxxIterator' 2016-06-23 01:01:46 +09:00
Yasuhiro Hatta f9df2e5c9d Code refactoring 2016-06-23 00:52:17 +09:00
Yasuhiro Hatta 1f2efdfd0f Code refactoring 2016-06-22 01:09:53 +09:00
Yasuhiro Hatta 58f9399e57 Code refactoring 2016-06-22 00:30:17 +09:00
Yasuhiro Hatta db64ab561f Add new algorithm 2016-06-21 01:23:20 +09:00
Yasuhiro Hatta 69ea597f6d Swift 3.0 2016-06-20 23:49:39 +09:00
Yasuhiro Hatta 27fbe635b9 Swift 3.0 2016-06-20 23:38:48 +09:00
Yasuhiro Hatta b29dfe4e94 Version 0.2.0 2016-06-14 01:25:50 +09:00
Yasuhiro Hatta b7e7815d8a Update README.md 2016-06-14 01:24:28 +09:00
Yasuhiro Hatta 36543bcdb5 Update tests 2016-06-14 01:21:18 +09:00
Yasuhiro Hatta 47f4cad5aa Add more unit tests 2016-06-13 01:04:31 +09:00
Yasuhiro Hatta d5e00a2832 Refactoring unit tests 2016-06-13 00:33:13 +09:00
Yasuhiro Hatta 484074ade5 Add subscript to CSV 2016-06-13 00:21:30 +09:00
Yasuhiro Hatta 7cb02fdc43 Add line break tests 2016-06-12 17:52:23 +09:00
Yasuhiro Hatta bec2704832 Add buffer size tests 2016-06-12 17:30:57 +09:00
Yasuhiro Hatta e3842e3db7 Add comments 2016-06-12 13:43:47 +09:00
Yasuhiro Hatta 0f1bbf9f89 Remove an unused property 2016-06-12 13:42:32 +09:00
Yasuhiro Hatta 8dd5eb1fb3 Update README.md 2016-06-11 18:50:13 +09:00
37 changed files with 4336 additions and 918 deletions

11
.swiftlint.yml Normal file
View File

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

View File

@ -1,17 +1,18 @@
Pod::Spec.new do |s|
s.name = 'CSV.swift'
s.version = '0.1.1'
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 }
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'
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.ios.deployment_target = '8.0'
spec.tvos.deployment_target = '9.0'
spec.watchos.deployment_target = '2.0'
spec.osx.deployment_target = '10.9'
s.module_name = 'CSV'
s.source_files = 'Sources/*.swift'
spec.module_name = 'CSV'
spec.swift_version = '5.0'
end

344
CSV.xcodeproj/project.pbxproj Normal file → Executable file
View File

@ -7,31 +7,72 @@
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 */; };
0E7E8C8C1D0BC7BB0057A1C1 /* CSV.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E7E8C811D0BC7BB0057A1C1 /* CSV.framework */; };
0E7E8CA01D0BC7F10057A1C1 /* ByteOrder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9C1D0BC7F10057A1C1 /* ByteOrder.swift */; };
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 */; };
0E7E8CBD1D0BC9D70057A1C1 /* ByteOrder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9C1D0BC7F10057A1C1 /* ByteOrder.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 */; };
0E7E8CDF1D0BCA8E0057A1C1 /* ByteOrder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9C1D0BC7F10057A1C1 /* ByteOrder.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 */; };
0E7E8CFF1D0BCDCF0057A1C1 /* ByteOrder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9C1D0BC7F10057A1C1 /* ByteOrder.swift */; };
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, ); }; };
0E7E8D031D0BCDDD0057A1C1 /* CSVReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8CA61D0BC8050057A1C1 /* CSVReaderTests.swift */; };
0E7E8D041D0BCDDD0057A1C1 /* CSVTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8CA71D0BC8050057A1C1 /* CSVTests.swift */; };
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 */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -40,14 +81,14 @@
containerPortal = 0E7E8C781D0BC7BB0057A1C1 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 0E7E8C801D0BC7BB0057A1C1;
remoteInfo = CSV;
remoteInfo = "CSV-iOS";
};
0E7E8CD11D0BCA2A0057A1C1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 0E7E8C781D0BC7BB0057A1C1 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 0E7E8CC51D0BCA2A0057A1C1;
remoteInfo = "CSV-OSX";
remoteInfo = "CSV-macOS";
};
0E7E8CF31D0BCD0B0057A1C1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
@ -59,21 +100,33 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
0E54021A1ED9DDF40019C3ED /* CSVWriterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSVWriterTests.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; };
0E7E8C9C1D0BC7F10057A1C1 /* ByteOrder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ByteOrder.swift; sourceTree = "<group>"; };
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-OSX.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "CSVTests-OSX.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
0E7E8CCF1D0BCA2A0057A1C1 /* CSVTests-macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "CSVTests-macOS.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>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -140,6 +193,7 @@
0E7E8C821D0BC7BB0057A1C1 /* Products */,
);
sourceTree = "<group>";
usesTabs = 0;
};
0E7E8C821D0BC7BB0057A1C1 /* Products */ = {
isa = PBXGroup;
@ -148,7 +202,7 @@
0E7E8C8B1D0BC7BB0057A1C1 /* CSVTests-iOS.xctest */,
0E7E8CB51D0BC98B0057A1C1 /* CSV.framework */,
0E7E8CC61D0BCA2A0057A1C1 /* CSV.framework */,
0E7E8CCF1D0BCA2A0057A1C1 /* CSVTests-OSX.xctest */,
0E7E8CCF1D0BCA2A0057A1C1 /* CSVTests-macOS.xctest */,
0E7E8CE81D0BCD0B0057A1C1 /* CSV.framework */,
0E7E8CF11D0BCD0B0057A1C1 /* CSVTests-tvOS.xctest */,
);
@ -158,9 +212,7 @@
0E7E8C9B1D0BC7F10057A1C1 /* Sources */ = {
isa = PBXGroup;
children = (
0E7E8C9C1D0BC7F10057A1C1 /* ByteOrder.swift */,
0E7E8C9D1D0BC7F10057A1C1 /* CSV.swift */,
0E7E8C9E1D0BC7F10057A1C1 /* CSVError.swift */,
0E959C5A208B611F005F8D01 /* CSV */,
0E7E8C9F1D0BC7F10057A1C1 /* CSVVersion.h */,
0E7E8CAC1D0BC8610057A1C1 /* Info.plist */,
);
@ -170,21 +222,43 @@
0E7E8CA41D0BC8050057A1C1 /* Tests */ = {
isa = PBXGroup;
children = (
0E7E8CA51D0BC8050057A1C1 /* CSV */,
0EA37AC81DD8C0B900F5B274 /* CSVTests */,
0E7E8CAE1D0BC8690057A1C1 /* Info.plist */,
);
path = Tests;
sourceTree = "<group>";
};
0E7E8CA51D0BC8050057A1C1 /* CSV */ = {
0E959C5A208B611F005F8D01 /* CSV */ = {
isa = PBXGroup;
children = (
0E7E8CA61D0BC8050057A1C1 /* CSVReaderTests.swift */,
0E7E8CA71D0BC8050057A1C1 /* CSVTests.swift */,
0E959C5E208B611F005F8D01 /* BinaryReader.swift */,
0E959C5D208B611F005F8D01 /* Legacy.swift */,
0E959C5B208B611F005F8D01 /* CSVError.swift */,
0E959C61208B611F005F8D01 /* CSVReader.swift */,
0E87607E219FF43B00C6C7FA /* CSVRowDecoder.swift */,
0E959C5C208B611F005F8D01 /* CSVWriter.swift */,
0E959C60208B611F005F8D01 /* Endian.swift */,
0E959C5F208B611F005F8D01 /* UnicodeIterator.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 */
@ -255,7 +329,7 @@
0E7E8C8E1D0BC7BB0057A1C1 /* PBXTargetDependency */,
);
name = "CSVTests-iOS";
productName = CSVTests;
productName = "CSVTests-iOS";
productReference = 0E7E8C8B1D0BC7BB0057A1C1 /* CSVTests-iOS.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
@ -277,10 +351,11 @@
productReference = 0E7E8CB51D0BC98B0057A1C1 /* CSV.framework */;
productType = "com.apple.product-type.framework";
};
0E7E8CC51D0BCA2A0057A1C1 /* CSV-OSX */ = {
0E7E8CC51D0BCA2A0057A1C1 /* CSV-macOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0E7E8CD71D0BCA2A0057A1C1 /* Build configuration list for PBXNativeTarget "CSV-OSX" */;
buildConfigurationList = 0E7E8CD71D0BCA2A0057A1C1 /* Build configuration list for PBXNativeTarget "CSV-macOS" */;
buildPhases = (
0E47EEBF1DBBC05700EBF783 /* Run Script () */,
0E7E8CC11D0BCA2A0057A1C1 /* Sources */,
0E7E8CC21D0BCA2A0057A1C1 /* Frameworks */,
0E7E8CC31D0BCA2A0057A1C1 /* Headers */,
@ -290,14 +365,14 @@
);
dependencies = (
);
name = "CSV-OSX";
productName = "CSV-OSX";
name = "CSV-macOS";
productName = "CSV-macOS";
productReference = 0E7E8CC61D0BCA2A0057A1C1 /* CSV.framework */;
productType = "com.apple.product-type.framework";
};
0E7E8CCE1D0BCA2A0057A1C1 /* CSVTests-OSX */ = {
0E7E8CCE1D0BCA2A0057A1C1 /* CSVTests-macOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0E7E8CDA1D0BCA2A0057A1C1 /* Build configuration list for PBXNativeTarget "CSVTests-OSX" */;
buildConfigurationList = 0E7E8CDA1D0BCA2A0057A1C1 /* Build configuration list for PBXNativeTarget "CSVTests-macOS" */;
buildPhases = (
0E7E8CCB1D0BCA2A0057A1C1 /* Sources */,
0E7E8CCC1D0BCA2A0057A1C1 /* Frameworks */,
@ -308,9 +383,9 @@
dependencies = (
0E7E8CD21D0BCA2A0057A1C1 /* PBXTargetDependency */,
);
name = "CSVTests-OSX";
productName = "CSV-OSXTests";
productReference = 0E7E8CCF1D0BCA2A0057A1C1 /* CSVTests-OSX.xctest */;
name = "CSVTests-macOS";
productName = "CSVTests-macOS";
productReference = 0E7E8CCF1D0BCA2A0057A1C1 /* CSVTests-macOS.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
0E7E8CE71D0BCD0B0057A1C1 /* CSV-tvOS */ = {
@ -345,7 +420,7 @@
0E7E8CF41D0BCD0B0057A1C1 /* PBXTargetDependency */,
);
name = "CSVTests-tvOS";
productName = "CSV-tvOSTests";
productName = "CSVTests-tvOS";
productReference = 0E7E8CF11D0BCD0B0057A1C1 /* CSVTests-tvOS.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
@ -355,50 +430,58 @@
0E7E8C781D0BC7BB0057A1C1 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0730;
LastSwiftUpdateCheck = 1010;
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = yaslab;
TargetAttributes = {
0E7E8C801D0BC7BB0057A1C1 = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1020;
};
0E7E8C8A1D0BC7BB0057A1C1 = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1020;
};
0E7E8CB41D0BC98B0057A1C1 = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0800;
};
0E7E8CC51D0BCA2A0057A1C1 = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1020;
};
0E7E8CCE1D0BCA2A0057A1C1 = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1020;
};
0E7E8CE71D0BCD0B0057A1C1 = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0800;
};
0E7E8CF01D0BCD0B0057A1C1 = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0930;
};
};
};
buildConfigurationList = 0E7E8C7B1D0BC7BB0057A1C1 /* Build configuration list for PBXProject "CSV" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 0E7E8C771D0BC7BB0057A1C1;
productRefGroup = 0E7E8C821D0BC7BB0057A1C1 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
0E7E8CC51D0BCA2A0057A1C1 /* CSV-OSX */,
0E7E8CC51D0BCA2A0057A1C1 /* CSV-macOS */,
0E7E8C801D0BC7BB0057A1C1 /* CSV-iOS */,
0E7E8CE71D0BCD0B0057A1C1 /* CSV-tvOS */,
0E7E8CB41D0BC98B0057A1C1 /* CSV-watchOS */,
0E7E8CCE1D0BCA2A0057A1C1 /* CSVTests-OSX */,
0E7E8CCE1D0BCA2A0057A1C1 /* CSVTests-macOS */,
0E7E8C8A1D0BC7BB0057A1C1 /* CSVTests-iOS */,
0E7E8CF01D0BCD0B0057A1C1 /* CSVTests-tvOS */,
);
@ -457,14 +540,36 @@
};
/* 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 = (
0E7E8CA11D0BC7F10057A1C1 /* CSV.swift in Sources */,
0E7E8CA21D0BC7F10057A1C1 /* CSVError.swift in Sources */,
0E7E8CA01D0BC7F10057A1C1 /* ByteOrder.swift in Sources */,
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 */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -472,8 +577,15 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0E7E8CAA1D0BC8050057A1C1 /* CSVTests.swift in Sources */,
0E7E8CA91D0BC8050057A1C1 /* CSVReaderTests.swift in Sources */,
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 */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -481,9 +593,14 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0E7E8CBE1D0BC9D70057A1C1 /* CSV.swift in Sources */,
0E7E8CBF1D0BC9D70057A1C1 /* CSVError.swift in Sources */,
0E7E8CBD1D0BC9D70057A1C1 /* ByteOrder.swift in Sources */,
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 */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -491,9 +608,14 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0E7E8CE01D0BCA8E0057A1C1 /* CSV.swift in Sources */,
0E7E8CE11D0BCA8E0057A1C1 /* CSVError.swift in Sources */,
0E7E8CDF1D0BCA8E0057A1C1 /* ByteOrder.swift in Sources */,
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 */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -501,8 +623,15 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0E7E8CDE1D0BCA840057A1C1 /* CSVTests.swift in Sources */,
0E7E8CDD1D0BCA840057A1C1 /* CSVReaderTests.swift in Sources */,
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 */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -510,9 +639,14 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0E7E8D001D0BCDCF0057A1C1 /* CSV.swift in Sources */,
0E7E8D011D0BCDCF0057A1C1 /* CSVError.swift in Sources */,
0E7E8CFF1D0BCDCF0057A1C1 /* ByteOrder.swift in Sources */,
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 */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -520,8 +654,15 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0E7E8D041D0BCDDD0057A1C1 /* CSVTests.swift in Sources */,
0E7E8D031D0BCDDD0057A1C1 /* CSVReaderTests.swift in Sources */,
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 */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -535,7 +676,7 @@
};
0E7E8CD21D0BCA2A0057A1C1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 0E7E8CC51D0BCA2A0057A1C1 /* CSV-OSX */;
target = 0E7E8CC51D0BCA2A0057A1C1 /* CSV-macOS */;
targetProxy = 0E7E8CD11D0BCA2A0057A1C1 /* PBXContainerItemProxy */;
};
0E7E8CF41D0BCD0B0057A1C1 /* PBXTargetDependency */ = {
@ -550,18 +691,29 @@
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";
@ -584,11 +736,13 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.9;
MTL_ENABLE_DEBUG_INFO = YES;
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 = "";
@ -599,18 +753,29 @@
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";
@ -627,9 +792,11 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
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";
@ -640,6 +807,7 @@
0E7E8C961D0BC7BB0057A1C1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@ -648,6 +816,7 @@
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;
@ -657,6 +826,7 @@
0E7E8C971D0BC7BB0057A1C1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@ -665,15 +835,18 @@
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";
};
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";
@ -684,10 +857,12 @@
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";
};
name = Release;
};
@ -695,6 +870,7 @@
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@ -702,6 +878,7 @@
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;
@ -715,6 +892,7 @@
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@ -722,10 +900,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";
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 2.0;
};
@ -745,6 +925,7 @@
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;
@ -766,22 +947,25 @@
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";
};
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-OSX";
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-macOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
};
@ -790,20 +974,23 @@
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-OSX";
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-macOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
};
name = Release;
};
0E7E8CFA1D0BCD0B0057A1C1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@ -811,6 +998,7 @@
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;
@ -823,6 +1011,7 @@
0E7E8CFB1D0BCD0B0057A1C1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@ -830,10 +1019,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";
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.0;
};
@ -842,6 +1033,7 @@
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";
@ -854,11 +1046,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";
TVOS_DEPLOYMENT_TARGET = 9.2;
};
name = Release;
@ -902,7 +1096,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0E7E8CD71D0BCA2A0057A1C1 /* Build configuration list for PBXNativeTarget "CSV-OSX" */ = {
0E7E8CD71D0BCA2A0057A1C1 /* Build configuration list for PBXNativeTarget "CSV-macOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0E7E8CD81D0BCA2A0057A1C1 /* Debug */,
@ -911,7 +1105,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0E7E8CDA1D0BCA2A0057A1C1 /* Build configuration list for PBXNativeTarget "CSVTests-OSX" */ = {
0E7E8CDA1D0BCA2A0057A1C1 /* Build configuration list for PBXNativeTarget "CSVTests-macOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0E7E8CDB1D0BCA2A0057A1C1 /* Debug */,

View File

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

View File

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

View File

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

View File

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

160
README.md
View File

@ -1,30 +1,38 @@
# 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 library written in Swift.
CSV reading and writing library written in Swift.
## Usage
## Usage for reading CSV
### From CSV string
### From string
```swift
import CSV
let csvString = "1,\"foo\"\n2,\"bar\""
for row in try! CSV(string: csvString) {
let csvString = "1,foo\n2,bar"
let csv = try! CSVReader(string: csvString)
while let row = csv.next() {
print("\(row)")
// => ["1", "foo"]
// => ["2", "bar"]
}
// => ["1", "foo"]
// => ["2", "bar"]
```
### From file path
### From file
NOTE: The default character encoding is `UTF8`.
```swift
import Foundation
import CSV
for row in try! CSV(path: "/path/to/file.csv") {
let stream = InputStream(fileAtPath: "/path/to/file.csv")!
let csv = try! CSVReader(stream: stream)
while let row = csv.next() {
print("\(row)")
}
```
@ -32,14 +40,34 @@ for row in try! CSV(path: "/path/to/file.csv") {
### Getting the header row
```swift
let csv = try! CSV(
path: "/path/to/file.csv",
hasHeaderRow: true) // default: false
import CSV
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"]
for row in csv {
// ...
while let row = csv.next() {
print("\(row)")
}
// => ["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.
while csv.next() != nil {
print("\(csv["id"]!)") // => "1"
print("\(csv["name"]!)") // => "foo"
}
```
@ -48,9 +76,92 @@ for row in csv {
If you use a file path, you can provide the character encoding to initializer.
```swift
let csv = try! CSV(
path: "/path/to/file.csv",
encoding: NSUTF8StringEncoding)
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()
```
## Installation
@ -58,26 +169,19 @@ let csv = try! CSV(
### CocoaPods
```ruby
pod 'CSV.swift', '~> 0.1'
pod 'CSV.swift', '~> 2.4.3'
```
### Carthage
```
github "yaslab/CSV.swift" ~> 0.1
github "yaslab/CSV.swift" ~> 2.4.3
```
### Swift Package Manager
```swift
import PackageDescription
let package = Package(
name: "PackageName",
dependencies: [
.Package(url: "https://github.com/yaslab/CSV.swift", majorVersion: 0, minor: 1)
]
)
.package(url: "https://github.com/yaslab/CSV.swift.git", .upToNextMinor(from: "2.4.3"))
```
## Reference specification
@ -86,4 +190,4 @@ let package = Package(
## License
CSV.swift is released under the MIT license. See the LICENSE file for more info.
CSV.swift is released under the MIT license. See the [LICENSE](https://github.com/yaslab/CSV.swift/blob/master/LICENSE) file for more info.

View File

@ -1,37 +0,0 @@
//
// ByteOrder.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/11.
//
//
import CoreFoundation
internal func ReadBigInt16(base: UnsafePointer<Void>, byteOffset: Int) -> UInt16 {
let bytes = UnsafePointer<UInt8>(base).advancedBy(byteOffset)
let int16Array = UnsafePointer<UInt16>(bytes)
return CFSwapInt16BigToHost(int16Array[0])
}
internal func ReadBigInt32(base: UnsafePointer<Void>, byteOffset: Int) -> UInt32 {
let bytes = UnsafePointer<UInt8>(base).advancedBy(byteOffset)
let int32Array = UnsafePointer<UInt32>(bytes)
return CFSwapInt32BigToHost(int32Array[0])
}
internal func ReadLittleInt16(base: UnsafePointer<Void>, byteOffset: Int) -> UInt16 {
let bytes = UnsafePointer<UInt8>(base).advancedBy(byteOffset)
let int16Array = UnsafePointer<UInt16>(bytes)
return CFSwapInt16LittleToHost(int16Array[0])
}
internal func ReadLittleInt32(base: UnsafePointer<Void>, byteOffset: Int) -> UInt32 {
let bytes = UnsafePointer<UInt8>(base).advancedBy(byteOffset)
let int32Array = UnsafePointer<UInt32>(bytes)
return CFSwapInt32LittleToHost(int32Array[0])
}
internal func IsBigEndian() -> Bool {
return CFByteOrderGetCurrent() == CFByteOrder(CFByteOrderBigEndian.rawValue)
}

View File

@ -1,395 +0,0 @@
//
// CSV.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/11.
//
//
import Foundation
private let LF: UInt32 = 0x0a //'\n'
private let CR: UInt32 = 0x0d //'\r'
private let DQUOTE: UInt32 = 0x22 //'"'
internal let defaultHasHeaderRow = false
internal let defaultEncoding = NSUTF8StringEncoding
internal let defaultDelimiter: CChar = 0x2c //','
internal let defaultBufferSize = 8192
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]
public class CSV: SequenceType, GeneratorType {
private let stream: NSInputStream
private let encoding: NSStringEncoding
private let delimiter: UInt32
private let bufferSize: Int
private var buffer: UnsafeMutablePointer<UInt8>!
private var bufferOffset: Int
private var lastReadCount: Int
private let charWidth: Int
private let fieldBuffer: NSMutableData
private var _headerRow: [String]? = nil
private var _currentRow: [String]? = nil
private var closed: Bool = false
public private(set) var lastError: CSVError? = nil
public init(
stream: NSInputStream,
hasHeaderRow: Bool = defaultHasHeaderRow,
encoding: NSStringEncoding = defaultEncoding,
delimiter: CChar = defaultDelimiter,
bufferSize: Int = defaultBufferSize)
throws
{
self.stream = stream
var bs = bufferSize
if bs < 0 {
throw CSVError.ParameterError
}
if bs < 8 {
bs = 8
}
self.bufferSize = bs + (4 - (bs % 4))
self.delimiter = UInt32(delimiter)
let b = malloc(bufferSize)
if b == nil {
throw CSVError.MemoryAllocationFailed
}
self.buffer = UnsafeMutablePointer<UInt8>(b)
self.bufferOffset = 0
self.fieldBuffer = NSMutableData()
if stream.streamStatus == .NotOpen {
stream.open()
}
if stream.streamStatus != .Open {
throw CSVError.StreamError
}
self.lastReadCount = stream.read(self.buffer, maxLength: bufferSize)
var e = encoding
switch encoding {
case NSUTF16StringEncoding,
NSUTF16BigEndianStringEncoding,
NSUTF16LittleEndianStringEncoding:
charWidth = 2
if encoding == NSUTF16StringEncoding {
let nativeEndian = IsBigEndian()
? NSUTF16BigEndianStringEncoding
: NSUTF16LittleEndianStringEncoding
e = nativeEndian
if lastReadCount >= charWidth {
if memcmp(buffer, utf16BigEndianBOM, charWidth) == 0 {
e = NSUTF16BigEndianStringEncoding
self.bufferOffset += charWidth
}
else if memcmp(buffer, utf16LittleEndianBOM, charWidth) == 0 {
e = NSUTF16LittleEndianStringEncoding
self.bufferOffset += charWidth
}
}
}
case NSUTF32StringEncoding,
NSUTF32BigEndianStringEncoding,
NSUTF32LittleEndianStringEncoding:
charWidth = 4
if encoding == NSUTF32StringEncoding {
let nativeEndian = IsBigEndian()
? NSUTF32BigEndianStringEncoding
: NSUTF32LittleEndianStringEncoding
e = nativeEndian
if lastReadCount >= charWidth {
if memcmp(buffer, utf32BigEndianBOM, charWidth) == 0 {
e = NSUTF32BigEndianStringEncoding
self.bufferOffset += charWidth
}
else if memcmp(buffer, utf32LittleEndianBOM, charWidth) == 0 {
e = NSUTF32LittleEndianStringEncoding
self.bufferOffset += charWidth
}
}
}
default:
charWidth = 1
if encoding == NSUTF8StringEncoding {
let bomSize = 3
if lastReadCount >= bomSize {
if memcmp(buffer, utf8BOM, charWidth) == 0 {
self.bufferOffset += bomSize
}
}
}
}
self.encoding = e
if hasHeaderRow {
guard let nextRow = next() else {
throw CSVError.HeaderReadError
}
_headerRow = nextRow
_currentRow = nil
}
}
deinit {
close()
}
public func close() {
if !closed {
stream.close()
if buffer != nil {
free(buffer)
buffer = nil
}
_headerRow = nil
_currentRow = nil
closed = true
}
}
public var headerRow: [String]? {
return _headerRow
}
public var currentRow: [String]? {
return _currentRow
}
// MARK: GeneratorType
public func next() -> [String]? {
fieldBuffer.length = 0
_currentRow = nil
if closed {
return nil
}
if lastReadCount <= 0 {
return nil
}
var fields = [String]()
var fieldStart = bufferOffset
var charLength = 0
var escaping = false
var quotationCount = 0
var prev: UInt32 = 0
while true {
if bufferOffset >= lastReadCount {
if charLength > 0 {
fieldBuffer.appendBytes(buffer + fieldStart, length: charWidth * charLength)
}
bufferOffset = 0
fieldStart = 0
charLength = 0
lastReadCount = stream.read(buffer, maxLength: bufferSize)
if lastReadCount < 0 {
// bad end
lastError = CSVError.StreamError
return nil
}
if lastReadCount == 0 {
// true end
break
}
}
var c: UInt32 = 0
switch encoding {
case NSUTF16BigEndianStringEncoding:
let _c = ReadBigInt16(buffer, byteOffset: bufferOffset)
c = UInt32(_c)
case NSUTF16LittleEndianStringEncoding:
let _c = ReadLittleInt16(buffer, byteOffset: bufferOffset)
c = UInt32(_c)
case NSUTF32BigEndianStringEncoding:
c = ReadBigInt32(buffer, byteOffset: bufferOffset)
case NSUTF32LittleEndianStringEncoding:
c = ReadLittleInt32(buffer, byteOffset: bufferOffset)
default: // multi-byte character encodings
let _c = (buffer + bufferOffset)[0]
c = UInt32(_c)
}
if c == DQUOTE {
quotationCount += 1
}
if c == DQUOTE && charLength == 0 {
escaping = true
}
if c == delimiter && prev == DQUOTE && (quotationCount % 2 == 0) {
escaping = false
}
if (c == CR || c == LF) && prev == DQUOTE && (quotationCount % 2 == 0) {
escaping = false
}
//
if prev == CR && c != LF && !escaping {
fieldBuffer.appendBytes(buffer + fieldStart, length: charWidth * charLength)
break
}
//
if c == LF && !escaping {
fieldBuffer.appendBytes(buffer + fieldStart, length: charWidth * charLength)
bufferOffset += charWidth
break
}
prev = c
//
if c == CR && !escaping {
bufferOffset += charWidth
continue
}
bufferOffset += charWidth
//
if c == delimiter && !escaping {
fieldBuffer.appendBytes(buffer + fieldStart, length: charWidth * charLength)
guard let field = getField(quotationCount) else {
return nil
}
fields.append(field)
// reset
fieldBuffer.length = 0
quotationCount = 0
charLength = 0
fieldStart = bufferOffset
}
else {
charLength += 1
}
}
guard let field = getField(quotationCount) else {
return nil
}
//
if isBufferEOF && fields.count == 0 && field.isEmpty {
return nil
}
fields.append(field)
_currentRow = fields
return fields
}
// MARK: Utility
private var isBufferEOF: Bool {
if stream.hasBytesAvailable {
return false
}
return bufferOffset >= (lastReadCount - 1)
}
private func getField(quotationCount: Int) -> String? {
guard var field = String(data: fieldBuffer, encoding: encoding) else {
lastError = CSVError.StringEncodingMismatch
return nil
}
if quotationCount >= 2
&& field.hasPrefix("\"")
&& field.hasSuffix("\"")
{
//let start = field.index(field.startIndex, offsetBy: 1)
//let end = field.index(field.endIndex, offsetBy: -1)
let start = field.startIndex.advancedBy(1)
let end = field.endIndex.advancedBy(-1)
field = field[start..<end]
}
if quotationCount >= 4 {
field = field.stringByReplacingOccurrencesOfString("\"\"", withString: "\"")
}
return field
}
}
extension CSV {
public convenience init(
path: String,
hasHeaderRow: Bool = defaultHasHeaderRow,
encoding: NSStringEncoding = defaultEncoding)
throws
{
guard let stream = NSInputStream(fileAtPath: path) else {
throw CSVError.StreamError
}
try self.init(stream: stream, hasHeaderRow: hasHeaderRow, encoding: encoding)
}
public convenience init(
url: NSURL,
hasHeaderRow: Bool = defaultHasHeaderRow,
encoding: NSStringEncoding = defaultEncoding)
throws
{
guard let stream = NSInputStream(URL: url) else {
throw CSVError.StreamError
}
try self.init(stream: stream, hasHeaderRow: hasHeaderRow, encoding: encoding)
}
public convenience init(
string: String,
hasHeaderRow: Bool = defaultHasHeaderRow)
throws
{
let encoding = defaultEncoding
guard let data = string.dataUsingEncoding(encoding) else {
throw CSVError.StringEncodingMismatch
}
let memoryStream = NSInputStream(data: data)
try self.init(stream: memoryStream, hasHeaderRow: hasHeaderRow, encoding: encoding)
}
}

View File

@ -0,0 +1,295 @@
//
// 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

@ -0,0 +1,29 @@
//
// CSVError.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/11.
// Copyright © 2016 yaslab. All rights reserved.
//
/// No overview available.
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
}

391
Sources/CSV/CSVReader.swift Normal file
View File

@ -0,0 +1,391 @@
//
// 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

@ -0,0 +1,749 @@
//
// 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
}()

211
Sources/CSV/CSVWriter.swift Normal file
View File

@ -0,0 +1,211 @@
//
// 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))
}
}
}

19
Sources/CSV/Endian.swift Normal file
View File

@ -0,0 +1,19 @@
//
// Endian.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/21.
// 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
}

12
Sources/CSV/Legacy.swift Normal file
View File

@ -0,0 +1,12 @@
//
// 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

@ -0,0 +1,35 @@
//
// UnicodeIterator.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/20.
// Copyright © 2016 yaslab. All rights reserved.
//
internal class UnicodeIterator<
Input: 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? {
switch inputEncoding.decode(&input) {
case .scalarValue(let c):
return c
case .emptyInput:
return nil
case .error:
errorHandler?(CSVError.unicodeDecoding)
return nil
}
}
}

View File

@ -1,17 +0,0 @@
//
// CSVError.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/11.
//
//
import Foundation
public enum CSVError: ErrorType {
case ParameterError
case StreamError
case HeaderReadError
case MemoryAllocationFailed
case StringEncodingMismatch
}

View File

@ -3,7 +3,7 @@
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/11.
//
// Copyright © 2016 yaslab. All rights reserved.
//
@import Foundation;

View File

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

View File

@ -1,229 +0,0 @@
//
// CSVReaderTests.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/11.
//
//
import XCTest
@testable import CSV
class CSVReaderTests: XCTestCase {
func testExample1() {
let csv = "abab,cdcd,efef"
let encoding = NSUTF8StringEncoding
let records = parseCSV(csv, encoding: encoding)
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
}
func testExample2() {
let csv = "abab,\"cdcd\",efef"
let encoding = NSUTF8StringEncoding
let records = parseCSV(csv, encoding: encoding)
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
}
func testExample3() {
let csv = "abab,cdcd,efef\nzxcv,asdf,qwer"
let encoding = NSUTF8StringEncoding
let records = parseCSV(csv, encoding: encoding)
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qwer"])
}
func testExample4() {
let csv = "abab,\"cd,cd\",efef"
let encoding = NSUTF8StringEncoding
let records = parseCSV(csv, encoding: encoding)
XCTAssertEqual(records[0], ["abab", "cd,cd", "efef"])
}
func testExample5() {
let csv = "abab,cdcd,efef\r\nzxcv,asdf,qwer"
let encoding = NSUTF8StringEncoding
let records = parseCSV(csv, encoding: encoding)
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qwer"])
}
func testExample6() {
let csv = "abab,\"\"\"cdcd\",efef\r\nzxcv,asdf,qwer"
let encoding = NSUTF8StringEncoding
let records = parseCSV(csv, encoding: encoding)
XCTAssertEqual(records[0], ["abab", "\"cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qwer"])
}
func testExample7() {
let csv = "abab,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\""
let encoding = NSUTF8StringEncoding
let records = parseCSV(csv, encoding: encoding)
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er"])
}
func testExample8() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = NSUTF8StringEncoding
let records = parseCSV(csv, encoding: encoding)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testExample9() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\",\r"
let encoding = NSUTF8StringEncoding
let records = parseCSV(csv, encoding: encoding)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testExample10() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\",\r\n"
let encoding = NSUTF8StringEncoding
let records = parseCSV(csv, encoding: encoding)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testExample11() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\",\n"
let encoding = NSUTF8StringEncoding
let records = parseCSV(csv, encoding: encoding)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testExample12() {
let csv = "abab,,\"\rcdcd\n\",efef\r\nzxcv,asdf,\"qw\"\"er\",\n"
let encoding = NSUTF8StringEncoding
let records = parseCSV(csv, encoding: encoding)
XCTAssertEqual(records.count, 2)
XCTAssertEqual(records[0], ["abab", "", "\rcdcd\n", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testEncodingWithoutBOM() {
var index = 0
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
for encoding in allEncodings() {
print("index: \(index)")
let records = parseCSV(csv, encoding: encoding)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
index += 1
}
}
func testUTF8WithBOM() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = NSUTF8StringEncoding
let mutableData = NSMutableData()
mutableData.appendBytes(utf8BOM, length: utf8BOM.count)
mutableData.appendData(csv.dataUsingEncoding(encoding)!)
let records = parseData(mutableData, encoding: encoding)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testUTF16WithNativeEndianBOM() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = NSUTF16StringEncoding
let records = parseCSV(csv, encoding: encoding)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testUTF16WithBigEndianBOM() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = NSUTF16StringEncoding
let mutableData = NSMutableData()
mutableData.appendBytes(utf16BigEndianBOM, length: utf16BigEndianBOM.count)
mutableData.appendData(csv.dataUsingEncoding(NSUTF16BigEndianStringEncoding)!)
let records = parseData(mutableData, encoding: encoding)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testUTF16WithLittleEndianBOM() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = NSUTF16StringEncoding
let mutableData = NSMutableData()
mutableData.appendBytes(utf16LittleEndianBOM, length: utf16LittleEndianBOM.count)
mutableData.appendData(csv.dataUsingEncoding(NSUTF16LittleEndianStringEncoding)!)
let records = parseData(mutableData, encoding: encoding)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testUTF32WithNativeEndianBOM() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = NSUTF32StringEncoding
let records = parseCSV(csv, encoding: encoding)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testUTF32WithBigEndianBOM() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = NSUTF32StringEncoding
let mutableData = NSMutableData()
mutableData.appendBytes(utf32BigEndianBOM, length: utf32BigEndianBOM.count)
mutableData.appendData(csv.dataUsingEncoding(NSUTF32BigEndianStringEncoding)!)
let records = parseData(mutableData, encoding: encoding)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func testUTF32WithLittleEndianBOM() {
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = NSUTF32StringEncoding
let mutableData = NSMutableData()
mutableData.appendBytes(utf32LittleEndianBOM, length: utf32LittleEndianBOM.count)
mutableData.appendData(csv.dataUsingEncoding(NSUTF32LittleEndianStringEncoding)!)
let records = parseData(mutableData, encoding: encoding)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
}
func allEncodings() -> [NSStringEncoding] {
return [
// multi-byte character encodings
NSShiftJISStringEncoding,
NSJapaneseEUCStringEncoding,
NSUTF8StringEncoding,
// wide character encodings
NSUTF16BigEndianStringEncoding,
NSUTF16LittleEndianStringEncoding,
NSUTF32BigEndianStringEncoding,
NSUTF32LittleEndianStringEncoding,
]
}
func parseCSV(csv: String, encoding: NSStringEncoding) -> [[String]] {
let data = csv.dataUsingEncoding(encoding)!
return parseData(data, encoding: encoding)
}
func parseData(data: NSData, encoding: NSStringEncoding) -> [[String]] {
let stream = NSInputStream(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),
]
}
}

View File

@ -1,87 +0,0 @@
//
// CSVTests.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/11.
//
//
import XCTest
@testable import CSV
class CSVTests: XCTestCase {
func testSample1() {
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 testSample2() {
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 testSample3() {
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 testSample4() {
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 testSample5() {
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)
}
}

View File

@ -0,0 +1,105 @@
//
// 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

@ -0,0 +1,242 @@
//
// 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

@ -0,0 +1,634 @@
//
// 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

@ -0,0 +1,336 @@
//
// 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

@ -0,0 +1,121 @@
//
// 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

@ -0,0 +1,104 @@
//
// 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

@ -0,0 +1,167 @@
//
// 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

@ -0,0 +1,113 @@
//
// 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

@ -0,0 +1,106 @@
//
// 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

@ -0,0 +1,196 @@
#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,14 +1,8 @@
//
// LinuxMain.swift
// CSV
//
// Created by Yasuhiro Hatta on 2016/06/11.
//
//
import XCTest
@testable import CSVTestSuite
XCTMain([
testCase(CSVReaderTests.allTests),
])
import CSVTests
var tests = [XCTestCaseEntry]()
tests += CSVTests.__allTests()
XCTMain(tests)