// Vikunja is a to-do list application to facilitate your life. // Copyright 2018-2020 Vikunja and contributors. All rights reserved. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . package wunderlist import ( "code.vikunja.io/api/pkg/config" "code.vikunja.io/api/pkg/files" "code.vikunja.io/api/pkg/models" "code.vikunja.io/api/pkg/timeutil" "github.com/stretchr/testify/assert" "gopkg.in/d4l3k/messagediff.v1" "io/ioutil" "strconv" "testing" "time" ) func TestWunderlistParsing(t *testing.T) { config.InitConfig() time1, err := time.Parse(time.RFC3339Nano, "2013-08-30T08:29:46.203Z") assert.NoError(t, err) time2, err := time.Parse(time.RFC3339Nano, "2013-08-30T08:36:13.273Z") assert.NoError(t, err) time3, err := time.Parse(time.RFC3339Nano, "2013-09-05T08:36:13.273Z") assert.NoError(t, err) time4, err := time.Parse(time.RFC3339Nano, "2013-08-02T11:58:55Z") assert.NoError(t, err) exampleFile, err := ioutil.ReadFile(config.ServiceRootpath.GetString() + "/pkg/modules/migration/wunderlist/testimage.jpg") assert.NoError(t, err) createTestTask := func(id, listID int, done bool) *task { completedAt, err := time.Parse(time.RFC3339Nano, "1970-01-01T00:00:00Z") assert.NoError(t, err) if done { completedAt = time1 } return &task{ ID: id, AssigneeID: 123, CreatedAt: time1, DueDate: "2013-09-05", ListID: listID, Title: "Ipsum" + strconv.Itoa(id), Completed: done, CompletedAt: completedAt, } } createTestNote := func(id, taskID int) *note { return ¬e{ ID: id, TaskID: taskID, Content: "Lorem Ipsum dolor sit amet", CreatedAt: time3, UpdatedAt: time2, } } fixtures := &wunderlistContents{ folders: []*folder{ { ID: 123, Title: "Lorem Ipsum", ListIds: []int{1, 2, 3, 4}, CreatedAt: time1, UpdatedAt: time2, }, }, lists: []*list{ { ID: 1, CreatedAt: time1, Title: "Lorem1", }, { ID: 2, CreatedAt: time1, Title: "Lorem2", }, { ID: 3, CreatedAt: time1, Title: "Lorem3", }, { ID: 4, CreatedAt: time1, Title: "Lorem4", }, { ID: 5, CreatedAt: time4, Title: "List without a namespace", }, }, tasks: []*task{ createTestTask(1, 1, false), createTestTask(2, 1, false), createTestTask(3, 2, true), createTestTask(4, 2, false), createTestTask(5, 3, false), createTestTask(6, 3, true), createTestTask(7, 3, true), createTestTask(8, 3, false), createTestTask(9, 4, true), createTestTask(10, 4, true), }, notes: []*note{ createTestNote(1, 1), createTestNote(2, 2), createTestNote(3, 3), }, files: []*file{ { ID: 1, URL: "https://vikunja.io/testimage.jpg", // Using an image which we are hosting, so it'll still be up TaskID: 1, ListID: 1, FileName: "file.md", ContentType: "text/plain", FileSize: 12345, CreatedAt: time2, UpdatedAt: time4, }, { ID: 2, URL: "https://vikunja.io/testimage.jpg", TaskID: 3, ListID: 2, FileName: "file2.md", ContentType: "text/plain", FileSize: 12345, CreatedAt: time3, UpdatedAt: time4, }, }, reminders: []*reminder{ { ID: 1, Date: time4, TaskID: 1, CreatedAt: time4, UpdatedAt: time4, }, { ID: 2, Date: time3, TaskID: 4, CreatedAt: time3, UpdatedAt: time3, }, }, subtasks: []*subtask{ { ID: 1, TaskID: 2, CreatedAt: time4, Title: "LoremSub1", }, { ID: 2, TaskID: 2, CreatedAt: time4, Title: "LoremSub2", }, { ID: 3, TaskID: 4, CreatedAt: time4, Title: "LoremSub3", }, }, } expectedHierachie := []*models.NamespaceWithLists{ { Namespace: models.Namespace{ Title: "Lorem Ipsum", Created: timeutil.FromTime(time1), Updated: timeutil.FromTime(time2), }, Lists: []*models.List{ { Created: timeutil.FromTime(time1), Title: "Lorem1", Tasks: []*models.Task{ { Title: "Ipsum1", DueDate: 1378339200, Created: timeutil.FromTime(time1), Description: "Lorem Ipsum dolor sit amet", Attachments: []*models.TaskAttachment{ { File: &files.File{ Name: "file.md", Mime: "text/plain", Size: 12345, Created: time2, CreatedUnix: timeutil.FromTime(time2), FileContent: exampleFile, }, Created: timeutil.FromTime(time2), }, }, Reminders: []timeutil.TimeStamp{timeutil.FromTime(time4)}, }, { Title: "Ipsum2", DueDate: 1378339200, Created: timeutil.FromTime(time1), Description: "Lorem Ipsum dolor sit amet", RelatedTasks: map[models.RelationKind][]*models.Task{ models.RelationKindSubtask: { { Title: "LoremSub1", }, { Title: "LoremSub2", }, }, }, }, }, }, { Created: timeutil.FromTime(time1), Title: "Lorem2", Tasks: []*models.Task{ { Title: "Ipsum3", Done: true, DoneAt: timeutil.FromTime(time1), DueDate: 1378339200, Created: timeutil.FromTime(time1), Description: "Lorem Ipsum dolor sit amet", Attachments: []*models.TaskAttachment{ { File: &files.File{ Name: "file2.md", Mime: "text/plain", Size: 12345, Created: time3, CreatedUnix: timeutil.FromTime(time3), FileContent: exampleFile, }, Created: timeutil.FromTime(time3), }, }, }, { Title: "Ipsum4", DueDate: 1378339200, Created: timeutil.FromTime(time1), Reminders: []timeutil.TimeStamp{timeutil.FromTime(time3)}, RelatedTasks: map[models.RelationKind][]*models.Task{ models.RelationKindSubtask: { { Title: "LoremSub3", }, }, }, }, }, }, { Created: timeutil.FromTime(time1), Title: "Lorem3", Tasks: []*models.Task{ { Title: "Ipsum5", DueDate: 1378339200, Created: timeutil.FromTime(time1), }, { Title: "Ipsum6", DueDate: 1378339200, Created: timeutil.FromTime(time1), Done: true, DoneAt: timeutil.FromTime(time1), }, { Title: "Ipsum7", DueDate: 1378339200, Created: timeutil.FromTime(time1), Done: true, DoneAt: timeutil.FromTime(time1), }, { Title: "Ipsum8", DueDate: 1378339200, Created: timeutil.FromTime(time1), }, }, }, { Created: timeutil.FromTime(time1), Title: "Lorem4", Tasks: []*models.Task{ { Title: "Ipsum9", DueDate: 1378339200, Created: timeutil.FromTime(time1), Done: true, DoneAt: timeutil.FromTime(time1), }, { Title: "Ipsum10", DueDate: 1378339200, Created: timeutil.FromTime(time1), Done: true, DoneAt: timeutil.FromTime(time1), }, }, }, }, }, { Namespace: models.Namespace{ Title: "Migrated from wunderlist", }, Lists: []*models.List{ { Created: timeutil.FromTime(time4), Title: "List without a namespace", }, }, }, } hierachie, err := convertWunderlistToVikunja(fixtures) assert.NoError(t, err) assert.NotNil(t, hierachie) if diff, equal := messagediff.PrettyDiff(hierachie, expectedHierachie); !equal { t.Errorf("ListUser.ReadAll() = %v, want %v, diff: %v", hierachie, expectedHierachie, diff) } }