Skip to content

Commit

Permalink
Merge 234cc45 into d63e1e2
Browse files Browse the repository at this point in the history
  • Loading branch information
vaskoz committed Sep 8, 2018
2 parents d63e1e2 + 234cc45 commit 61ee597
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 0 deletions.
8 changes: 8 additions & 0 deletions infinitescroll/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Infinite Scroll List

The problem is to design an infinite scroll list like you'd see in a
webpage.

The implementation should know how many total sites are possible for a
list. Then *AddSites* is called to add more to your current list. Your
list should be able to answer questions about sites not yet loaded too.
92 changes: 92 additions & 0 deletions infinitescroll/problem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package infinitescroll

// Checkbox represents the state of the select all checkbox
type Checkbox int

const (
// Checked is when the select all box is selected.
Checked Checkbox = iota
// Unchecked is when the select all box is deselected.
Unchecked
// Indeterminate is when the select all box is greyed out.
Indeterminate
)

type table struct {
currentState Checkbox
sites map[string]bool
totalCount, clickCount uint64
}

// Table represents an infinite scroll list in a webpage.
type Table interface {
AddSites(sites []string)
ToggleSelectAll()
CurrentState() Checkbox
IsClicked(site string) bool
Click(site string)
}

// NewTable creates a new instance of an Table
func NewTable(totalCount uint64) Table {
return &table{sites: make(map[string]bool),
currentState: Unchecked, totalCount: totalCount}
}

func (ist *table) AddSites(sites []string) {
click := ist.CurrentState() == Checked
for _, site := range sites {
ist.sites[site] = click
}
if click {
ist.clickCount += uint64(len(sites))
}
}

func (ist *table) ToggleSelectAll() {
if ist.currentState == Checked {
ist.currentState = Unchecked
toggleAll(ist.sites, false)
ist.clickCount = 0
} else {
ist.currentState = Checked
toggleAll(ist.sites, true)
ist.clickCount = uint64(len(ist.sites))
}
}

func toggleAll(sites map[string]bool, click bool) {
for site := range sites {
sites[site] = click
}
}

func (ist *table) CurrentState() Checkbox { return ist.currentState }

func (ist *table) IsClicked(site string) bool {
if ist.currentState == Checked {
return true
} else if ist.currentState == Unchecked {
return false
}
return ist.sites[site]
}

func (ist *table) Click(site string) {
if state := ist.CurrentState(); state == Unchecked || state == Checked {
ist.currentState = Indeterminate
}
clicked := ist.sites[site]
ist.sites[site] = !clicked
if clicked {
ist.clickCount--
} else {
ist.clickCount++
}
if ist.clickCount == 0 {
ist.currentState = Unchecked
}
if ist.clickCount == ist.totalCount {
ist.currentState = Checked
}
}
99 changes: 99 additions & 0 deletions infinitescroll/problem_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package infinitescroll

import "testing"

func TestClickThenUnclick(t *testing.T) {
t.Parallel()
table := NewTable(3000)
table.AddSites([]string{"google", "yahoo", "microsoft", "amazon"})
table.Click("amazon")
if result := table.CurrentState(); result != Indeterminate {
t.Errorf("Expected Indeterminate but got %v", result)
}
table.Click("amazon")
if result := table.CurrentState(); result != Unchecked {
t.Errorf("Expected Unchecked but got %v", result)
}
}

func TestIsClickForSeenAndUnseen(t *testing.T) {
t.Parallel()
table := NewTable(5)
table.AddSites([]string{"google", "yahoo", "microsoft", "amazon"})
if clicked := table.IsClicked("unseen"); clicked {
t.Errorf("Should be unclicked")
}
if selectAll := table.CurrentState(); selectAll != Unchecked {
t.Errorf("Table should be unchecked for all here")
}
table.Click("amazon")
if selectAll := table.CurrentState(); selectAll != Indeterminate {
t.Errorf("Table should be indeterminate because 1 site is clicked")
}
if clicked := table.IsClicked("unseen"); clicked {
t.Errorf("Should be unclicked")
}
}

func TestToggleAll(t *testing.T) {
t.Parallel()
table := NewTable(3)
table.AddSites([]string{"google", "yahoo"})
table.ToggleSelectAll()
if clicked := table.IsClicked("google"); !clicked {
t.Errorf("Google should be clicked because of the toggle select all")
}
if clicked := table.IsClicked("yahoo"); !clicked {
t.Errorf("Yahoo should be clicked because of the toggle select all")
}
if clicked := table.IsClicked("amazon"); !clicked {
t.Errorf("Unseen Amazon should be clicked because of the toggle select all")
}
table.AddSites([]string{"amazon"})
table.ToggleSelectAll()
if clicked := table.IsClicked("google"); clicked {
t.Errorf("Google should be unclicked because of the toggle select all")
}
if clicked := table.IsClicked("yahoo"); clicked {
t.Errorf("Yahoo should be unclicked because of the toggle select all")
}
if clicked := table.IsClicked("amazon"); clicked {
t.Errorf("Amazon should be unclicked because of the toggle select all")
}
}

func TestToggleAllWithClicks(t *testing.T) {
t.Parallel()
table := NewTable(3)
table.ToggleSelectAll()
table.AddSites([]string{"google", "yahoo"})
if state := table.CurrentState(); state != Checked {
t.Errorf("Table should be checked for select all")
}
table.Click("google")
if state := table.CurrentState(); state != Indeterminate {
t.Errorf("Table should be indeterminate after a deselect click")
}
table.ToggleSelectAll()
if state := table.CurrentState(); state != Checked {
t.Errorf("Table should be select all")
}
}

func TestManuallySelectTotalSites(t *testing.T) {
t.Parallel()
table := NewTable(3)
table.AddSites([]string{"google", "yahoo", "amazon"})
if state := table.CurrentState(); state != Unchecked {
t.Errorf("Table should be unchecked")
}
table.Click("google")
table.Click("yahoo")
if state := table.CurrentState(); state != Indeterminate {
t.Errorf("Table should be indeterminate after two clicks")
}
table.Click("amazon")
if state := table.CurrentState(); state != Checked {
t.Errorf("Everything manually checked up to the total size")
}
}

0 comments on commit 61ee597

Please sign in to comment.