| 1 | //! Store tests against an in-memory SQLite database. |
| 2 | |
| 3 | const std = @import("std"); |
| 4 | const testing = std.testing; |
| 5 | const Store = @import("db.zig").Store; |
| 6 | |
| 7 | fn titles(todos: anytype) ![]const u8 { |
| 8 | var out: std.Io.Writer.Allocating = .init(testing.allocator); |
| 9 | errdefer out.deinit(); |
| 10 | for (todos) |t| try out.writer.print("{s}{s};", .{ if (t.completed) "x " else "", t.title }); |
| 11 | return out.toOwnedSlice(); |
| 12 | } |
| 13 | |
| 14 | fn expectList(store: *Store, list: i64, want: []const u8) !void { |
| 15 | var arena: std.heap.ArenaAllocator = .init(testing.allocator); |
| 16 | defer arena.deinit(); |
| 17 | const got = try titles(try store.todos(arena.allocator(), list)); |
| 18 | defer testing.allocator.free(got); |
| 19 | try testing.expectEqualStrings(want, got); |
| 20 | } |
| 21 | |
| 22 | test "lists are separate and every action is scoped to its list" { |
| 23 | var store = try Store.open(testing.io, ":memory:"); |
| 24 | defer store.close(); |
| 25 | |
| 26 | const a = try store.createList("hash-a"); |
| 27 | const b = try store.createList("hash-b"); |
| 28 | try testing.expectEqual(a, (try store.findList("hash-a")).?); |
| 29 | try testing.expectEqual(null, try store.findList("hash-c")); |
| 30 | |
| 31 | try store.add(a, "one"); |
| 32 | try store.add(a, "two"); |
| 33 | try store.add(b, "theirs"); |
| 34 | try expectList(&store, a, "one;two;"); |
| 35 | |
| 36 | var arena: std.heap.ArenaAllocator = .init(testing.allocator); |
| 37 | defer arena.deinit(); |
| 38 | const theirs = (try store.todos(arena.allocator(), b))[0].id; |
| 39 | try testing.expect(!try store.toggle(a, theirs)); |
| 40 | try testing.expect(!try store.rename(a, theirs, "mine now")); |
| 41 | try testing.expect(!try store.destroy(a, theirs)); |
| 42 | try expectList(&store, b, "theirs;"); |
| 43 | |
| 44 | const two = (try store.todos(arena.allocator(), a))[1].id; |
| 45 | try testing.expect(try store.toggle(a, two)); |
| 46 | try expectList(&store, a, "one;x two;"); |
| 47 | try testing.expect(try store.rename(a, two, "2 ✓")); |
| 48 | try expectList(&store, a, "one;x 2 ✓;"); |
| 49 | } |
| 50 | |
| 51 | test "toggle all, then back, then clear completed" { |
| 52 | var store = try Store.open(testing.io, ":memory:"); |
| 53 | defer store.close(); |
| 54 | const a = try store.createList("hash-a"); |
| 55 | try store.add(a, "one"); |
| 56 | try store.add(a, "two"); |
| 57 | |
| 58 | try store.toggleAll(a); |
| 59 | try expectList(&store, a, "x one;x two;"); |
| 60 | try store.toggleAll(a); |
| 61 | try expectList(&store, a, "one;two;"); |
| 62 | |
| 63 | var arena: std.heap.ArenaAllocator = .init(testing.allocator); |
| 64 | defer arena.deinit(); |
| 65 | _ = try store.toggle(a, (try store.todos(arena.allocator(), a))[0].id); |
| 66 | try store.toggleAll(a); |
| 67 | try expectList(&store, a, "x one;x two;"); |
| 68 | |
| 69 | try store.clearCompleted(a); |
| 70 | try expectList(&store, a, ""); |
| 71 | } |
| 72 | |