Merge pull request #344 from shikorism/feature/319-csv-importer

CheckinCsvImporter
This commit is contained in:
shibafu
2020-05-18 01:05:58 +09:00
committed by GitHub
32 changed files with 800 additions and 3 deletions

View File

@@ -0,0 +1,268 @@
<?php
namespace Tests\Unit\Services;
use App\Ejaculation;
use App\Exceptions\CsvImportException;
use App\Services\CheckinCsvImporter;
use App\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Carbon;
use Tests\TestCase;
class CheckinCsvImporterTest extends TestCase
{
use RefreshDatabase;
protected function setUp()
{
parent::setUp();
$this->seed();
}
public function testIncompatibleCharsetEUCJP()
{
$user = factory(User::class)->create();
$this->expectException(CsvImportException::class);
$this->expectExceptionMessage('文字コード判定に失敗しました。UTF-8 (BOM無し) または Shift_JIS をお使いください。');
$importer = new CheckinCsvImporter($user, __DIR__ . '/../../fixture/Csv/incompatible-charset.eucjp.csv');
$importer->execute();
}
/**
* @dataProvider provideMissingTime
*/
public function testMissingTime($filename)
{
$user = factory(User::class)->create();
$this->expectException(CsvImportException::class);
$this->expectExceptionMessage('日時列は必須です。');
$importer = new CheckinCsvImporter($user, $filename);
$importer->execute();
}
public function provideMissingTime()
{
return [
'UTF8' => [__DIR__ . '/../../fixture/Csv/missing-time.utf8.csv'],
'SJIS' => [__DIR__ . '/../../fixture/Csv/missing-time.sjis.csv'],
];
}
/**
* @dataProvider provideDate
*/
public function testDate($expectedDate, $filename)
{
$user = factory(User::class)->create();
$importer = new CheckinCsvImporter($user, $filename);
$importer->execute();
$ejaculation = $user->ejaculations()->first();
$this->assertSame(1, $user->ejaculations()->count());
$this->assertEquals($expectedDate, $ejaculation->ejaculated_date);
}
public function provideDate()
{
$date = Carbon::create(2020, 1, 23, 6, 1, 0, 'Asia/Tokyo');
return [
'Zero, Second, UTF8' => [$date, __DIR__ . '/../../fixture/Csv/date.utf8.csv'],
'NoZero, Second, UTF8' => [$date, __DIR__ . '/../../fixture/Csv/date-nozero.utf8.csv'],
'Zero, NoSecond, UTF8' => [$date, __DIR__ . '/../../fixture/Csv/date-nosecond.utf8.csv'],
'NoZero, NoSecond, UTF8' => [$date, __DIR__ . '/../../fixture/Csv/date-nozero-nosecond.utf8.csv'],
];
}
public function testInvalidDate()
{
$user = factory(User::class)->create();
try {
$importer = new CheckinCsvImporter($user, __DIR__ . '/../../fixture/Csv/invalid-date.utf8.csv');
$importer->execute();
} catch (CsvImportException $e) {
$this->assertSame('2 行 : 日時は 2000/01/01 00:00 〜 2099/12/31 23:59 の間のみ対応しています。', $e->getErrors()[0]);
$this->assertSame('3 行 : 日時は 2000/01/01 00:00 〜 2099/12/31 23:59 の間のみ対応しています。', $e->getErrors()[1]);
$this->assertSame('4 行 : 日時の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[2]);
$this->assertSame('5 行 : 日時の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[3]);
$this->assertSame('6 行 : 日時の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[4]);
$this->assertSame('7 行 : 日時の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[5]);
$this->assertSame('8 行 : 日時の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[6]);
$this->assertSame('9 行 : 日時の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[7]);
$this->assertSame('10 行 : 日時の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[8]);
$this->assertSame('11 行 : 日時の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[9]);
$this->assertSame('12 行 : 日時の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[10]);
$this->assertSame('13 行 : 日時の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[11]);
$this->assertSame('14 行 : 日時の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[12]);
$this->assertSame('15 行 : 日時の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[13]);
$this->assertSame('16 行 : 日時の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[14]);
$this->assertSame('17 行 : 日時の形式は "年/月/日 時:分" にしてください。', $e->getErrors()[15]);
return;
}
$this->fail('期待する例外が発生していません');
}
public function testNoteUTF8()
{
$user = factory(User::class)->create();
$importer = new CheckinCsvImporter($user, __DIR__ . '/../../fixture/Csv/note.utf8.csv');
$importer->execute();
$ejaculations = $user->ejaculations()->orderBy('ejaculated_date')->get();
$this->assertCount(3, $ejaculations);
$this->assertEquals('The quick brown fox jumps over the lazy dog. 素早い茶色の狐はのろまな犬を飛び越える', $ejaculations[0]->note);
$this->assertEquals("The quick brown fox jumps over the lazy dog.\n素早い茶色の狐はのろまな犬を飛び越える", $ejaculations[1]->note);
$this->assertEquals('The quick brown fox jumps over the "lazy" dog.', $ejaculations[2]->note);
}
/**
* @dataProvider provideNoteOverLength
*/
public function testNoteOverLength($filename)
{
$user = factory(User::class)->create();
$this->expectException(CsvImportException::class);
$this->expectExceptionMessage('2 行 : ートには500文字以下の文字列を指定してください。');
$importer = new CheckinCsvImporter($user, $filename);
$importer->execute();
}
public function provideNoteOverLength()
{
return [
'ASCII Only, UTF8' => [__DIR__ . '/../../fixture/Csv/note-over-length.ascii.utf8.csv'],
'JP, UTF8' => [__DIR__ . '/../../fixture/Csv/note-over-length.jp.utf8.csv'],
];
}
public function testLinkUTF8()
{
$user = factory(User::class)->create();
$importer = new CheckinCsvImporter($user, __DIR__ . '/../../fixture/Csv/link.utf8.csv');
$importer->execute();
$ejaculations = $user->ejaculations()->orderBy('ejaculated_date')->get();
$this->assertCount(1, $ejaculations);
$this->assertEquals('http://example.com', $ejaculations[0]->link);
}
public function testLinkOverLengthUTF8()
{
$user = factory(User::class)->create();
$this->expectException(CsvImportException::class);
$this->expectExceptionMessage('3 行 : オカズリンクには2000文字以下の文字列を指定してください。');
$importer = new CheckinCsvImporter($user, __DIR__ . '/../../fixture/Csv/link-over-length.utf8.csv');
$importer->execute();
}
public function testLinkIsNotUrlUTF8()
{
$user = factory(User::class)->create();
$this->expectException(CsvImportException::class);
$this->expectExceptionMessage('2 行 : オカズリンクには正しい形式のURLを指定してください。');
$importer = new CheckinCsvImporter($user, __DIR__ . '/../../fixture/Csv/link-not-url.utf8.csv');
$importer->execute();
}
public function testTag1UTF8()
{
$user = factory(User::class)->create();
$importer = new CheckinCsvImporter($user, __DIR__ . '/../../fixture/Csv/tag1.utf8.csv');
$importer->execute();
$ejaculation = $user->ejaculations()->first();
$tags = $ejaculation->tags()->get();
$this->assertSame(1, $user->ejaculations()->count());
$this->assertCount(1, $tags);
$this->assertEquals('貧乳', $tags[0]->name);
}
public function testTag2UTF8()
{
$user = factory(User::class)->create();
$importer = new CheckinCsvImporter($user, __DIR__ . '/../../fixture/Csv/tag2.utf8.csv');
$importer->execute();
$ejaculation = $user->ejaculations()->first();
$tags = $ejaculation->tags()->get();
$this->assertSame(1, $user->ejaculations()->count());
$this->assertCount(2, $tags);
$this->assertEquals('貧乳', $tags[0]->name);
$this->assertEquals('巨乳', $tags[1]->name);
}
public function testTagOverLengthUTF8()
{
$user = factory(User::class)->create();
$this->expectException(CsvImportException::class);
$this->expectExceptionMessage('3 行 : タグ1は255文字以内にしてください。');
$importer = new CheckinCsvImporter($user, __DIR__ . '/../../fixture/Csv/tag-over-length.utf8.csv');
$importer->execute();
}
public function testTagCanAcceptJumpedColumnUTF8()
{
$user = factory(User::class)->create();
$importer = new CheckinCsvImporter($user, __DIR__ . '/../../fixture/Csv/tag-jumped-column.utf8.csv');
$importer->execute();
$ejaculation = $user->ejaculations()->first();
$tags = $ejaculation->tags()->get();
$this->assertSame(1, $user->ejaculations()->count());
$this->assertCount(2, $tags);
$this->assertEquals('貧乳', $tags[0]->name);
$this->assertEquals('巨乳', $tags[1]->name);
}
public function testTagCantAcceptMultilineUTF8()
{
$user = factory(User::class)->create();
$this->expectException(CsvImportException::class);
$this->expectExceptionMessage('2 行 : タグ1に改行を含めることはできません。');
$importer = new CheckinCsvImporter($user, __DIR__ . '/../../fixture/Csv/tag-multiline.utf8.csv');
$importer->execute();
}
public function testTagCanAccept32ColumnsUTF8()
{
$user = factory(User::class)->create();
$importer = new CheckinCsvImporter($user, __DIR__ . '/../../fixture/Csv/tag-33-column.utf8.csv');
$importer->execute();
$ejaculation = $user->ejaculations()->first();
$tags = $ejaculation->tags()->get();
$this->assertSame(1, $user->ejaculations()->count());
$this->assertCount(32, $tags);
$this->assertEquals('み', $tags[31]->name);
}
public function testSourceIsCsv()
{
$user = factory(User::class)->create();
$importer = new CheckinCsvImporter($user, __DIR__ . '/../../fixture/Csv/date.utf8.csv');
$importer->execute();
$ejaculation = $user->ejaculations()->first();
$this->assertSame(1, $user->ejaculations()->count());
$this->assertEquals(Ejaculation::SOURCE_CSV, $ejaculation->source);
}
}

2
tests/fixture/Csv/.editorconfig vendored Normal file
View File

@@ -0,0 +1,2 @@
[*.csv]
end_of_line = crlf

View File

@@ -0,0 +1,2 @@
日時
2020/01/23 06:01
1 日時
2 2020/01/23 06:01

View File

@@ -0,0 +1,2 @@
日時
2020/1/23 6:01
1 日時
2 2020/1/23 6:01

View File

@@ -0,0 +1,2 @@
日時
2020/1/23 6:01:02
1 日時
2 2020/1/23 6:01:02

2
tests/fixture/Csv/date.utf8.csv vendored Normal file
View File

@@ -0,0 +1,2 @@
日時
2020/01/23 06:01:02
1 日時
2 2020/01/23 06:01:02

View File

@@ -0,0 +1,2 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD>Ρ<EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
2019/1/01 0:01,<EFBFBD>ƥ<EFBFBD><EFBFBD>ȥƥ<EFBFBD><EFBFBD>Ȥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,https://example.com/
1 日時 ノート オカズリンク
2 2019/1/01 0:01 テストテストあああああ https://example.com/

17
tests/fixture/Csv/invalid-date.utf8.csv vendored Normal file
View File

@@ -0,0 +1,17 @@
日時,ノート
1999/12/31 23:59:59,最小境界
2100/01/01 00:00:00,最大境界
-1/01/01 00:00:00,存在しない日付
2019/-1/01 00:00:00,存在しない日付
2019/01/-1 00:00:00,存在しない日付
2019/02/29 00:00:00,存在しない日付
2019/00/01 00:00:00,存在しない日付
2019/01/00 00:00:00,存在しない日付
2019/01/32 00:00:00,存在しない日付
2019/13/01 00:00:00,存在しない日付
2019/01/01 00:60:00,存在しない時刻
2019/01/01 24:00:00,存在しない時刻
2019/01/01 00:00:60,存在しない時刻
2019/01/01 -1:00:00,存在しない時刻
2019/01/01 00:-1:00,存在しない時刻
2019/01/01 00:00:-1,存在しない時刻
1 日時 ノート
2 1999/12/31 23:59:59 最小境界
3 2100/01/01 00:00:00 最大境界
4 -1/01/01 00:00:00 存在しない日付
5 2019/-1/01 00:00:00 存在しない日付
6 2019/01/-1 00:00:00 存在しない日付
7 2019/02/29 00:00:00 存在しない日付
8 2019/00/01 00:00:00 存在しない日付
9 2019/01/00 00:00:00 存在しない日付
10 2019/01/32 00:00:00 存在しない日付
11 2019/13/01 00:00:00 存在しない日付
12 2019/01/01 00:60:00 存在しない時刻
13 2019/01/01 24:00:00 存在しない時刻
14 2019/01/01 00:00:60 存在しない時刻
15 2019/01/01 -1:00:00 存在しない時刻
16 2019/01/01 00:-1:00 存在しない時刻
17 2019/01/01 00:00:-1 存在しない時刻

View File

@@ -0,0 +1,3 @@
日時,オカズリンク
2020/01/23 06:01,example
1 日時 オカズリンク
2 2020/01/23 06:01 example

View File

@@ -0,0 +1,3 @@
日時,オカズリンク
2020/01/23 06:01,https://example.com/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/exam
2020/01/23 06:01,https://example.com/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/examp
1 日時 オカズリンク
2 2020/01/23 06:01 https://example.com/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/exam
3 2020/01/23 06:01 https://example.com/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/example/examp

2
tests/fixture/Csv/link.utf8.csv vendored Normal file
View File

@@ -0,0 +1,2 @@
日時,オカズリンク
2020/01/23 06:01,http://example.com
1 日時 オカズリンク
2 2020/01/23 06:01 http://example.com

View File

@@ -0,0 +1 @@
<EFBFBD>m<EFBFBD>[<5B>g,<EFBFBD>I<EFBFBD>J<EFBFBD>Y<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>N,<EFBFBD>^<5E>O1
1 ノート オカズリンク タグ1

View File

@@ -0,0 +1 @@
ノート,オカズリンク,タグ1
1 ノート オカズリンク タグ1

View File

@@ -0,0 +1,2 @@
日時,ノート
2020/01/23 06:01,oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooox
1 日時 ノート
2 2020/01/23 06:01 oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooox

View File

@@ -0,0 +1,2 @@
日時,ノート
2020/01/23 06:01,ああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああい
1 日時 ノート
2 2020/01/23 06:01 ああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああい

5
tests/fixture/Csv/note.utf8.csv vendored Normal file
View File

@@ -0,0 +1,5 @@
日時,ノート
2020/01/23 06:01,The quick brown fox jumps over the lazy dog. 素早い茶色の狐はのろまな犬を飛び越える
2020/01/23 06:02,"The quick brown fox jumps over the lazy dog.
素早い茶色の狐はのろまな犬を飛び越える"
2020/01/23 06:03,"The quick brown fox jumps over the ""lazy"" dog."
1 日時 ノート
2 2020/01/23 06:01 The quick brown fox jumps over the lazy dog. 素早い茶色の狐はのろまな犬を飛び越える
3 2020/01/23 06:02 The quick brown fox jumps over the lazy dog. 素早い茶色の狐はのろまな犬を飛び越える
4 2020/01/23 06:03 The quick brown fox jumps over the "lazy" dog.

View File

@@ -0,0 +1,2 @@
日時,タグ1,タグ2,タグ3,タグ4,タグ5,タグ6,タグ7,タグ8,タグ9,タグ10,タグ11,タグ12,タグ13,タグ14,タグ15,タグ16,タグ17,タグ18,タグ19,タグ20,タグ21,タグ22,タグ23,タグ24,タグ25,タグ26,タグ27,タグ28,タグ29,タグ30,タグ31,タグ32,タグ33
2020/01/23 06:01,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
1 日時 タグ1 タグ2 タグ3 タグ4 タグ5 タグ6 タグ7 タグ8 タグ9 タグ10 タグ11 タグ12 タグ13 タグ14 タグ15 タグ16 タグ17 タグ18 タグ19 タグ20 タグ21 タグ22 タグ23 タグ24 タグ25 タグ26 タグ27 タグ28 タグ29 タグ30 タグ31 タグ32 タグ33
2 2020/01/23 06:01

View File

@@ -0,0 +1,2 @@
日時,タグ1,タグ3
2020/01/23 06:01,貧乳,巨乳
1 日時 タグ1 タグ3
2 2020/01/23 06:01 貧乳 巨乳

View File

@@ -0,0 +1,3 @@
日時,タグ1
2020/01/23 06:01,"複数行の
タグ"
1 日時 タグ1
2 2020/01/23 06:01 複数行の タグ

View File

@@ -0,0 +1,3 @@
日時,タグ1
2020/01/23 06:01,ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
2020/01/23 06:02,ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooox
1 日時 タグ1
2 2020/01/23 06:01 ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
3 2020/01/23 06:02 ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooox

2
tests/fixture/Csv/tag1.utf8.csv vendored Normal file
View File

@@ -0,0 +1,2 @@
日時,タグ1
2020/01/23 06:01,貧乳
1 日時 タグ1
2 2020/01/23 06:01 貧乳

2
tests/fixture/Csv/tag2.utf8.csv vendored Normal file
View File

@@ -0,0 +1,2 @@
日時,タグ1,タグ2
2020/01/23 06:01,貧乳,巨乳
1 日時 タグ1 タグ2
2 2020/01/23 06:01 貧乳 巨乳