From de613a7ad9ac450d8375629be8952bfbb4b1e852 Mon Sep 17 00:00:00 2001 From: Cassie Recher Date: Fri, 13 Aug 2021 21:39:10 +0000 Subject: [PATCH 01/12] Add tests for ListNode. --- claat/nodes/list.go | 31 ++++++++++++ claat/nodes/list_test.go | 101 +++++++++++++++++++++++++++++++++++++++ claat/nodes/node.go | 28 ----------- 3 files changed, 132 insertions(+), 28 deletions(-) create mode 100644 claat/nodes/list.go create mode 100644 claat/nodes/list_test.go diff --git a/claat/nodes/list.go b/claat/nodes/list.go new file mode 100644 index 000000000..a7e2114a5 --- /dev/null +++ b/claat/nodes/list.go @@ -0,0 +1,31 @@ +package nodes + +// NewListNode creates a new Node of type NodeList. +func NewListNode(nodes ...Node) *ListNode { + n := &ListNode{node: node{typ: NodeList}} + n.Append(nodes...) + return n +} + +// ListNode contains other nodes. +type ListNode struct { + node + Nodes []Node +} + +// Empty returns true if all l.Nodes are empty. +func (l *ListNode) Empty() bool { + return EmptyNodes(l.Nodes) +} + +// TODO remove +// Append appends nodes n to the end of l.Nodes slice. +func (l *ListNode) Append(n ...Node) { + l.Nodes = append(l.Nodes, n...) +} + +// TODO remove +// Prepend prepends nodes n at the beginning of l.Nodes slice. +func (l *ListNode) Prepend(n ...Node) { + l.Nodes = append(n, l.Nodes...) +} diff --git a/claat/nodes/list_test.go b/claat/nodes/list_test.go new file mode 100644 index 000000000..9af203d0e --- /dev/null +++ b/claat/nodes/list_test.go @@ -0,0 +1,101 @@ +package nodes + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +var cmpOptList = cmp.AllowUnexported(ListNode{}, node{}, TextNode{}) + +func TestNewListNode(t *testing.T) { + tests := []struct { + name string + inNodes []Node + out *ListNode + }{ + { + name: "Empty", + out: &ListNode{ + node: node{typ: NodeList}, + }, + }, + { + name: "One", + inNodes: []Node{ + NewTextNode("foo"), + }, + out: &ListNode{ + node: node{typ: NodeList}, + Nodes: []Node{ + NewTextNode("foo"), + }, + }, + }, + { + name: "Multiple", + inNodes: []Node{ + NewTextNode("foo"), + NewTextNode("bar"), + NewTextNode("baz"), + }, + out: &ListNode{ + node: node{typ: NodeList}, + Nodes: []Node{ + NewTextNode("foo"), + NewTextNode("bar"), + NewTextNode("baz"), + }, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + out := NewListNode(tc.inNodes...) + if diff := cmp.Diff(tc.out, out, cmpOptList); diff != "" { + t.Errorf("NewListNode(%v) got diff (-want +got): %s", tc.inNodes, diff) + return + } + }) + } +} + +func TestListNodeEmpty(t *testing.T) { + tests := []struct { + name string + inNodes []Node + out bool + }{ + { + name: "Empty", + out: true, + }, + { + name: "NonEmpty", + inNodes: []Node{ + NewTextNode("foo"), + NewTextNode("bar"), + NewTextNode("baz"), + }, + }, + { + name: "EmptyWithNodes", + inNodes: []Node{ + NewTextNode(""), + NewTextNode(""), + NewTextNode(""), + }, + out: true, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + n := NewListNode(tc.inNodes...) + out := n.Empty() + if out != tc.out { + t.Errorf("ListNode.Empty() = %t, want %t", out, tc.out) + return + } + }) + } +} diff --git a/claat/nodes/node.go b/claat/nodes/node.go index 943d8e748..b6e8ccadd 100644 --- a/claat/nodes/node.go +++ b/claat/nodes/node.go @@ -126,34 +126,6 @@ func (b *node) MutateEnv(e []string) { sort.Strings(b.env) } -// NewListNode creates a new Node of type NodeList. -func NewListNode(nodes ...Node) *ListNode { - n := &ListNode{node: node{typ: NodeList}} - n.Append(nodes...) - return n -} - -// ListNode contains other nodes. -type ListNode struct { - node - Nodes []Node -} - -// Empty returns true if all l.Nodes are empty. -func (l *ListNode) Empty() bool { - return EmptyNodes(l.Nodes) -} - -// Append appends nodes n to the end of l.Nodes slice. -func (l *ListNode) Append(n ...Node) { - l.Nodes = append(l.Nodes, n...) -} - -// Prepend prepends nodes n at the beginning of l.Nodes slice. -func (l *ListNode) Prepend(n ...Node) { - l.Nodes = append(n, l.Nodes...) -} - // NewImportNode creates a new Node of type NodeImport, // with initialized ImportNode.Content. func NewImportNode(url string) *ImportNode { From 8037e9ad49a53f3a1a59104d8217b086adb04932 Mon Sep 17 00:00:00 2001 From: Cassie Recher Date: Fri, 13 Aug 2021 21:41:30 +0000 Subject: [PATCH 02/12] Remove unused function. --- claat/nodes/list.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/claat/nodes/list.go b/claat/nodes/list.go index a7e2114a5..86b405cca 100644 --- a/claat/nodes/list.go +++ b/claat/nodes/list.go @@ -23,9 +23,3 @@ func (l *ListNode) Empty() bool { func (l *ListNode) Append(n ...Node) { l.Nodes = append(l.Nodes, n...) } - -// TODO remove -// Prepend prepends nodes n at the beginning of l.Nodes slice. -func (l *ListNode) Prepend(n ...Node) { - l.Nodes = append(n, l.Nodes...) -} From a56c745c987df414e75efb7571a13878873e39cc Mon Sep 17 00:00:00 2001 From: Cassie Recher Date: Fri, 13 Aug 2021 22:14:45 +0000 Subject: [PATCH 03/12] Remove TODO --- claat/nodes/node.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/claat/nodes/node.go b/claat/nodes/node.go index b6e8ccadd..76dfac503 100644 --- a/claat/nodes/node.go +++ b/claat/nodes/node.go @@ -14,8 +14,6 @@ package nodes -// TODO be consistent between Node/*Node - import ( "sort" ) From 3d470c8b00756233f57172b6ccb865d9867b6fa5 Mon Sep 17 00:00:00 2001 From: Cassie Recher Date: Fri, 13 Aug 2021 23:37:00 +0000 Subject: [PATCH 04/12] Add some tests for ImportNode. --- claat/nodes/import.go | 51 +++++++++++++++++++++ claat/nodes/import_test.go | 91 ++++++++++++++++++++++++++++++++++++++ claat/nodes/node.go | 50 --------------------- 3 files changed, 142 insertions(+), 50 deletions(-) create mode 100644 claat/nodes/import.go create mode 100644 claat/nodes/import_test.go diff --git a/claat/nodes/import.go b/claat/nodes/import.go new file mode 100644 index 000000000..9cf5bf21c --- /dev/null +++ b/claat/nodes/import.go @@ -0,0 +1,51 @@ +package nodes + +// NewImportNode creates a new Node of type NodeImport, +// with initialized ImportNode.Content. +func NewImportNode(url string) *ImportNode { + return &ImportNode{ + node: node{typ: NodeImport}, + Content: NewListNode(), + URL: url, + } +} + +// ImportNode indicates a remote resource available at ImportNode.URL. +type ImportNode struct { + node + URL string + Content *ListNode +} + +// Empty returns the result of in.Content.Empty method. +func (in *ImportNode) Empty() bool { + return in.Content.Empty() +} + +// MutateBlock mutates both in's block marker and that of in.Content. +func (in *ImportNode) MutateBlock(v interface{}) { + in.node.MutateBlock(v) + in.Content.MutateBlock(v) +} + +// ImportNodes extracts everything except NodeImport nodes, recursively. +func ImportNodes(nodes []Node) []*ImportNode { + var imps []*ImportNode + for _, n := range nodes { + switch n := n.(type) { + case *ImportNode: + imps = append(imps, n) + case *ListNode: + imps = append(imps, ImportNodes(n.Nodes)...) + case *InfoboxNode: + imps = append(imps, ImportNodes(n.Content.Nodes)...) + case *GridNode: + for _, r := range n.Rows { + for _, c := range r { + imps = append(imps, ImportNodes(c.Content.Nodes)...) + } + } + } + } + return imps +} diff --git a/claat/nodes/import_test.go b/claat/nodes/import_test.go new file mode 100644 index 000000000..a5ade471f --- /dev/null +++ b/claat/nodes/import_test.go @@ -0,0 +1,91 @@ +package nodes + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +var cmpOptImport = cmp.AllowUnexported(ImportNode{}, node{}, ListNode{}, TextNode{}) + +func TestNewImportNode(t *testing.T) { + tests := []struct { + name string + inURL string + out *ImportNode + }{ + { + name: "Empty", + out: &ImportNode{ + node: node{typ: NodeImport}, + Content: NewListNode(), + }, + }, + { + name: "HasURL", + inURL: "google.com", + out: &ImportNode{ + node: node{typ: NodeImport}, + URL: "google.com", + Content: NewListNode(), + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + out := NewImportNode(tc.inURL) + if diff := cmp.Diff(tc.out, out, cmpOptImport); diff != "" { + t.Errorf("NewImportNode(%q) got diff (-want +got): %s", tc.inURL, diff) + return + } + }) + } +} + +func TestImportNodeEmpty(t *testing.T) { + a := NewImportNode("") + a.Content.Nodes = append(a.Content.Nodes, NewTextNode("a")) + b := NewImportNode("foobar") + b.Content.Nodes = append(b.Content.Nodes, NewTextNode("b")) + c := NewImportNode("foobar") + c.Content.Nodes = append(c.Content.Nodes, NewTextNode("")) + + tests := []struct { + name string + inNode *ImportNode + out bool + }{ + { + name: "EmptyNoURL", + inNode: NewImportNode(""), + out: true, + }, + { + name: "EmptyWithURL", + inNode: NewImportNode("google.com"), + out: true, + }, + { + name: "NonEmptyNoURL", + inNode: a, + }, + { + name: "NonEmptyWithURL", + inNode: b, + }, + { + name: "EmptyWithContent", + inNode: c, + out: true, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + out := tc.inNode.Empty() + if out != tc.out { + t.Errorf("ImageNode.Empty() = %t, want %t", out, tc.out) + return + } + }) + } +} diff --git a/claat/nodes/node.go b/claat/nodes/node.go index 76dfac503..5787e792f 100644 --- a/claat/nodes/node.go +++ b/claat/nodes/node.go @@ -124,56 +124,6 @@ func (b *node) MutateEnv(e []string) { sort.Strings(b.env) } -// NewImportNode creates a new Node of type NodeImport, -// with initialized ImportNode.Content. -func NewImportNode(url string) *ImportNode { - return &ImportNode{ - node: node{typ: NodeImport}, - Content: NewListNode(), - URL: url, - } -} - -// ImportNode indicates a remote resource available at ImportNode.URL. -type ImportNode struct { - node - URL string - Content *ListNode -} - -// Empty returns the result of in.Content.Empty method. -func (in *ImportNode) Empty() bool { - return in.Content.Empty() -} - -// MutateBlock mutates both in's block marker and that of in.Content. -func (in *ImportNode) MutateBlock(v interface{}) { - in.node.MutateBlock(v) - in.Content.MutateBlock(v) -} - -// ImportNodes extracts everything except NodeImport nodes, recursively. -func ImportNodes(nodes []Node) []*ImportNode { - var imps []*ImportNode - for _, n := range nodes { - switch n := n.(type) { - case *ImportNode: - imps = append(imps, n) - case *ListNode: - imps = append(imps, ImportNodes(n.Nodes)...) - case *InfoboxNode: - imps = append(imps, ImportNodes(n.Content.Nodes)...) - case *GridNode: - for _, r := range n.Rows { - for _, c := range r { - imps = append(imps, ImportNodes(c.Content.Nodes)...) - } - } - } - } - return imps -} - // NewItemsListNode creates a new ItemsListNode of type NodeItemsList, // which defaults to an unordered list. // Provide a positive start to make this a numbered list. From 3c888767066aacedbdf78e57f1acdc0f48ae769e Mon Sep 17 00:00:00 2001 From: Cassie Recher Date: Sat, 14 Aug 2021 00:11:52 +0000 Subject: [PATCH 05/12] Add more tests for ImportNode. --- claat/nodes/import_test.go | 93 +++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/claat/nodes/import_test.go b/claat/nodes/import_test.go index a5ade471f..299b3717d 100644 --- a/claat/nodes/import_test.go +++ b/claat/nodes/import_test.go @@ -83,7 +83,98 @@ func TestImportNodeEmpty(t *testing.T) { t.Run(tc.name, func(t *testing.T) { out := tc.inNode.Empty() if out != tc.out { - t.Errorf("ImageNode.Empty() = %t, want %t", out, tc.out) + t.Errorf("ImportNode.Empty() = %t, want %t", out, tc.out) + return + } + }) + } +} + +func TestImportNodes(t *testing.T) { + a1 := NewImportNode("google.com") + a2 := NewImportNode("youtube.com") + a3 := NewImportNode("google.com/calendar") + + b1 := NewGridNode( + []*GridCell{ + &GridCell{ + Rowspan: 1, + Colspan: 1, + Content: NewListNode(NewTextNode("aaa"), NewTextNode("bbb")), + }, + &GridCell{ + Rowspan: 1, + Colspan: 1, + Content: NewListNode(a1, NewTextNode("ccc")), + }, + }, + []*GridCell{ + &GridCell{ + Rowspan: 1, + Colspan: 1, + Content: NewListNode(NewTextNode("ddd"), a3), + }, + &GridCell{ + Rowspan: 1, + Colspan: 1, + Content: NewListNode(a2, NewTextNode("eee")), + }, + }, + ) + + c1 := NewInfoboxNode(InfoboxNegative, a1, NewTextNode("foobar")) + c2 := NewListNode(a2, NewButtonNode(false, false, false, NewTextNode("foobar"))) + c3 := NewListNode(c1, c2, a3) + + tests := []struct { + name string + inNodes []Node + out []*ImportNode + }{ + { + name: "JustImport", + inNodes: []Node{a1}, + out: []*ImportNode{a1}, + }, + { + name: "Multiple", + inNodes: []Node{a1, NewTextNode("foo"), a2, NewTextNode("bar"), a3}, + out: []*ImportNode{a1, a2, a3}, + }, + { + name: "List", + inNodes: []Node{NewListNode(a1, a2, a3)}, + out: []*ImportNode{a1, a2, a3}, + }, + { + name: "Infobox", + inNodes: []Node{NewInfoboxNode(InfoboxPositive, a1, a2, NewTextNode("foobar"), a3)}, + out: []*ImportNode{a1, a2, a3}, + }, + { + name: "Grid", + inNodes: []Node{b1}, + out: []*ImportNode{a1, a3, a2}, + }, + { + name: "Button", + inNodes: []Node{NewButtonNode(true, true, true, a3, a2, a1)}, + }, + { + name: "Text", + inNodes: []Node{NewTextNode("foobar")}, + }, + { + name: "NontrivialStructure", + inNodes: []Node{c3}, + out: []*ImportNode{a1, a2, a3}, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + out := ImportNodes(tc.inNodes) + if diff := cmp.Diff(tc.out, out, cmpOptImport); diff != "" { + t.Errorf("ImportNodes(%+v) got diff (-want +got): %s", tc.inNodes, diff) return } }) From d244bc7691a299e03c81c800e635a07578a56244 Mon Sep 17 00:00:00 2001 From: Cassie Recher Date: Mon, 16 Aug 2021 20:58:43 +0000 Subject: [PATCH 06/12] Test ImportNode's MutateBlock. --- claat/nodes/import_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/claat/nodes/import_test.go b/claat/nodes/import_test.go index 299b3717d..e2ff5c6da 100644 --- a/claat/nodes/import_test.go +++ b/claat/nodes/import_test.go @@ -90,6 +90,20 @@ func TestImportNodeEmpty(t *testing.T) { } } +func TestImportNodeMutateBlock(t *testing.T) { + n := NewImportNode("") + mValue := "foobar" + + n.MutateBlock(mValue) + + if n.node.block != mValue { + t.Errorf("ImportNode.node.block = %+v, want %q", n.node.block, mValue) + } + if n.Content.node.block != mValue { + t.Errorf("ImportNode.Content.node.block = %+v, want %q", n.Content.node.block, mValue) + } +} + func TestImportNodes(t *testing.T) { a1 := NewImportNode("google.com") a2 := NewImportNode("youtube.com") From c2e50a2971df3308a2107da7080aed7ec233f019 Mon Sep 17 00:00:00 2001 From: Cassie Recher Date: Mon, 16 Aug 2021 21:39:15 +0000 Subject: [PATCH 07/12] Move isHeader to header.go. Not adding tests because I can't think of any that aren't change detectors. --- claat/nodes/header.go | 5 +++++ claat/nodes/node.go | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/claat/nodes/header.go b/claat/nodes/header.go index c1a84af4b..820ac2403 100644 --- a/claat/nodes/header.go +++ b/claat/nodes/header.go @@ -20,3 +20,8 @@ type HeaderNode struct { func (hn *HeaderNode) Empty() bool { return hn.Content.Empty() } + +// IsHeader returns true if t is one of header types. +func IsHeader(t NodeType) bool { + return t&(NodeHeader|NodeHeaderCheck|NodeHeaderFAQ) != 0 +} diff --git a/claat/nodes/node.go b/claat/nodes/node.go index 5787e792f..f8c2f208e 100644 --- a/claat/nodes/node.go +++ b/claat/nodes/node.go @@ -70,11 +70,6 @@ func IsItemsList(t NodeType) bool { return t&(NodeItemsList|NodeItemsCheck|NodeItemsFAQ) != 0 } -// IsHeader returns true if t is one of header types. -func IsHeader(t NodeType) bool { - return t&(NodeHeader|NodeHeaderCheck|NodeHeaderFAQ) != 0 -} - // IsInline returns true if t is an inline node type. func IsInline(t NodeType) bool { return t&(NodeText|NodeURL|NodeImage|NodeButton) != 0 From 2c3728726df2b27c917adc84161883344ec4dc0f Mon Sep 17 00:00:00 2001 From: Cassie Recher Date: Mon, 16 Aug 2021 21:51:59 +0000 Subject: [PATCH 08/12] Add test for EmptyNodes. --- claat/nodes/node_test.go | 65 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 claat/nodes/node_test.go diff --git a/claat/nodes/node_test.go b/claat/nodes/node_test.go new file mode 100644 index 000000000..a59ffac9b --- /dev/null +++ b/claat/nodes/node_test.go @@ -0,0 +1,65 @@ +package nodes + +import ( + "testing" +) + +func TestEmptyNodes(t *testing.T) { + tests := []struct { + name string + inNodes []Node + out bool + }{ + { + name: "Zero", + out: true, + }, + { + name: "OneEmpty", + inNodes: []Node{ + NewTextNode(""), + }, + out: true, + }, + { + name: "OneNonEmpty", + inNodes: []Node{ + NewTextNode("foo"), + }, + }, + { + name: "MultipleEmpty", + inNodes: []Node{ + NewTextNode(""), + NewTextNode(""), + NewTextNode(""), + }, + out: true, + }, + { + name: "MultipleSomeNonEmpty", + inNodes: []Node{ + NewTextNode("foo"), + NewTextNode(""), + NewTextNode("bar"), + }, + }, + { + name: "MultipleAllNonEmpty", + inNodes: []Node{ + NewTextNode("foo"), + NewTextNode("bar"), + NewTextNode("baz"), + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + out := EmptyNodes(tc.inNodes) + if out != tc.out { + t.Errorf("EmptyNodes(%+v) = %t, want %t", tc.inNodes, out, tc.out) + return + } + }) + } +} From 2a54ee44b59dc88b3f92fc3c32ee59c078d1c11d Mon Sep 17 00:00:00 2001 From: Cassie Recher Date: Mon, 16 Aug 2021 21:56:56 +0000 Subject: [PATCH 09/12] Add some TODOs. --- claat/nodes/node.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/claat/nodes/node.go b/claat/nodes/node.go index f8c2f208e..68749e6ec 100644 --- a/claat/nodes/node.go +++ b/claat/nodes/node.go @@ -95,6 +95,7 @@ func (b *node) Type() NodeType { return b.typ } +// TODO test func (b *node) MutateType(t NodeType) { if IsItemsList(b.typ) && IsItemsList(t) || IsHeader(b.typ) && IsHeader(t) { b.typ = t @@ -113,12 +114,14 @@ func (b *node) Env() []string { return b.env } +// TODO test func (b *node) MutateEnv(e []string) { b.env = make([]string, len(e)) copy(b.env, e) sort.Strings(b.env) } +// TODO test ItemsList related code // NewItemsListNode creates a new ItemsListNode of type NodeItemsList, // which defaults to an unordered list. // Provide a positive start to make this a numbered list. From 9cf71d6a680cdaff2a52cadff39328edf6e99229 Mon Sep 17 00:00:00 2001 From: Cassie Recher Date: Mon, 16 Aug 2021 22:21:14 +0000 Subject: [PATCH 10/12] Create separate file for ItemsListNode. --- claat/nodes/itemslist.go | 43 ++++++++++++++++++++++++++++++++++++++++ claat/nodes/node.go | 42 --------------------------------------- 2 files changed, 43 insertions(+), 42 deletions(-) create mode 100644 claat/nodes/itemslist.go diff --git a/claat/nodes/itemslist.go b/claat/nodes/itemslist.go new file mode 100644 index 000000000..1d7a6f54c --- /dev/null +++ b/claat/nodes/itemslist.go @@ -0,0 +1,43 @@ +package nodes + +// TODO test ItemsList related code +// NewItemsListNode creates a new ItemsListNode of type NodeItemsList, +// which defaults to an unordered list. +// Provide a positive start to make this a numbered list. +// NodeItemsCheck and NodeItemsFAQ are always unnumbered. +func NewItemsListNode(typ string, start int) *ItemsListNode { + iln := ItemsListNode{ + node: node{typ: NodeItemsList}, + // TODO document this + ListType: typ, + Start: start, + } + iln.MutateBlock(true) + return &iln +} + +// ItemsListNode containts sets of ListNode. +// Non-zero ListType indicates an ordered list. +type ItemsListNode struct { + node + ListType string + Start int + Items []*ListNode +} + +// Empty returns true if every item has empty content. +func (il *ItemsListNode) Empty() bool { + for _, i := range il.Items { + if !i.Empty() { + return false + } + } + return true +} + +// NewItem creates a new ListNode and adds it to il.Items. +func (il *ItemsListNode) NewItem(nodes ...Node) *ListNode { + n := NewListNode(nodes...) + il.Items = append(il.Items, n) + return n +} diff --git a/claat/nodes/node.go b/claat/nodes/node.go index 68749e6ec..fe4483fb0 100644 --- a/claat/nodes/node.go +++ b/claat/nodes/node.go @@ -120,45 +120,3 @@ func (b *node) MutateEnv(e []string) { copy(b.env, e) sort.Strings(b.env) } - -// TODO test ItemsList related code -// NewItemsListNode creates a new ItemsListNode of type NodeItemsList, -// which defaults to an unordered list. -// Provide a positive start to make this a numbered list. -// NodeItemsCheck and NodeItemsFAQ are always unnumbered. -func NewItemsListNode(typ string, start int) *ItemsListNode { - iln := ItemsListNode{ - node: node{typ: NodeItemsList}, - // TODO document this - ListType: typ, - Start: start, - } - iln.MutateBlock(true) - return &iln -} - -// ItemsListNode containts sets of ListNode. -// Non-zero ListType indicates an ordered list. -type ItemsListNode struct { - node - ListType string - Start int - Items []*ListNode -} - -// Empty returns true if every item has empty content. -func (il *ItemsListNode) Empty() bool { - for _, i := range il.Items { - if !i.Empty() { - return false - } - } - return true -} - -// NewItem creates a new ListNode and adds it to il.Items. -func (il *ItemsListNode) NewItem(nodes ...Node) *ListNode { - n := NewListNode(nodes...) - il.Items = append(il.Items, n) - return n -} From 07a639f5ed480644c642699420a104d48248ea99 Mon Sep 17 00:00:00 2001 From: Cassie Recher Date: Tue, 17 Aug 2021 00:32:11 +0000 Subject: [PATCH 11/12] Add some tests for ItemsListNode. --- claat/nodes/itemslist.go | 1 - claat/nodes/itemslist_test.go | 88 +++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 claat/nodes/itemslist_test.go diff --git a/claat/nodes/itemslist.go b/claat/nodes/itemslist.go index 1d7a6f54c..89c953303 100644 --- a/claat/nodes/itemslist.go +++ b/claat/nodes/itemslist.go @@ -1,6 +1,5 @@ package nodes -// TODO test ItemsList related code // NewItemsListNode creates a new ItemsListNode of type NodeItemsList, // which defaults to an unordered list. // Provide a positive start to make this a numbered list. diff --git a/claat/nodes/itemslist_test.go b/claat/nodes/itemslist_test.go new file mode 100644 index 000000000..23e1f6553 --- /dev/null +++ b/claat/nodes/itemslist_test.go @@ -0,0 +1,88 @@ +package nodes + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +var cmpOptItemsList = cmp.AllowUnexported(ItemsListNode{}, node{}) + +func TestNewItemsListNode(t *testing.T) { + // Only one code path, so this is not a tabular test. + inTyp := "foobar" + inStart := 5 + got := NewItemsListNode(inTyp, inStart) + want := &ItemsListNode{ + node: node{ + typ: NodeItemsList, + block: true, + }, + ListType: "foobar", + Start: 5, + } + + if diff := cmp.Diff(want, got, cmpOptItemsList); diff != "" { + t.Errorf("NewItemsListNode(%q, %d) got diff (-want +got): %s", inTyp, inStart, diff) + } +} + +func TestItemsListNodeEmpty(t *testing.T) { + a := NewItemsListNode("foobar", 0) + a.Items = append(a.Items, NewListNode(NewTextNode(""))) + + b := NewItemsListNode("foobar", 0) + b.Items = append(b.Items, NewListNode(NewTextNode("a"))) + + c := NewItemsListNode("foobar", 0) + c.Items = append(c.Items, NewListNode(NewTextNode("")), NewListNode(NewTextNode("")), NewListNode(NewTextNode(""))) + + d := NewItemsListNode("foobar", 0) + d.Items = append(d.Items, NewListNode(NewTextNode("a")), NewListNode(NewTextNode("")), NewListNode(NewTextNode("b"))) + + e := NewItemsListNode("foobar", 0) + e.Items = append(e.Items, NewListNode(NewTextNode("a")), NewListNode(NewTextNode("b")), NewListNode(NewTextNode("c"))) + + tests := []struct { + name string + inNode *ItemsListNode + out bool + }{ + { + name: "Zero", + inNode: NewItemsListNode("foobar", 0), + out: true, + }, + { + name: "OneEmpty", + inNode: a, + out: true, + }, + { + name: "OneNonEmpty", + inNode: b, + }, + { + name: "MultipleEmpty", + inNode: c, + out: true, + }, + { + name: "MultipleSomeNonEmpty", + inNode: d, + }, + { + name: "MultipleAllNonEmpty", + inNode: e, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + out := tc.inNode.Empty() + if out != tc.out { + t.Errorf("ItemsListNode.Empty() = %t, want %t", out, tc.out) + return + } + }) + } +} From 5d251cd411dab528db2bb24f4300829d1c834742 Mon Sep 17 00:00:00 2001 From: Cassie Recher Date: Tue, 17 Aug 2021 21:56:19 +0000 Subject: [PATCH 12/12] Add more tests for ItemsListNode. --- claat/nodes/itemslist_test.go | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/claat/nodes/itemslist_test.go b/claat/nodes/itemslist_test.go index 23e1f6553..9304e14f4 100644 --- a/claat/nodes/itemslist_test.go +++ b/claat/nodes/itemslist_test.go @@ -6,7 +6,7 @@ import ( "github.com/google/go-cmp/cmp" ) -var cmpOptItemsList = cmp.AllowUnexported(ItemsListNode{}, node{}) +var cmpOptItemsList = cmp.AllowUnexported(ItemsListNode{}, node{}, ListNode{}, TextNode{}) func TestNewItemsListNode(t *testing.T) { // Only one code path, so this is not a tabular test. @@ -86,3 +86,36 @@ func TestItemsListNodeEmpty(t *testing.T) { }) } } + +func TestItemsListNewItem(t *testing.T) { + // Only one code path, so this is not a tabular test. + a := NewTextNode("a") + b := NewTextNode("b") + c := NewTextNode("c") + + iln := NewItemsListNode("foobar", 0) + + got := iln.NewItem(a, b, c) + want := NewListNode(a, b, c) + + if diff := cmp.Diff(want, got, cmpOptItemsList); diff != "" { + t.Errorf("ItemsListNode.NewItem() got diff (-want +got): %s", diff) + } + + wantItemsListNode := &ItemsListNode{ + node: node{ + typ: NodeItemsList, + block: true, + }, + ListType: "foobar", + Items: []*ListNode{ + &ListNode{ + node: node{typ: NodeList}, + Nodes: []Node{a, b, c}, + }, + }, + } + if diff := cmp.Diff(wantItemsListNode, iln, cmpOptItemsList); diff != "" { + t.Errorf("ItemsListNode after NewItem got diff ((-want +got): %s", diff) + } +}