Skip to content

Commit b0f173b

Browse files
kamilonKennedy Bushnell
andauthored
Add unit tests and bug fixes to Spells Overview (#55)
Co-authored-by: Kennedy Bushnell <kennedyb@microsoft.com>
1 parent 2fb0927 commit b0f173b

File tree

4 files changed

+1853
-102
lines changed

4 files changed

+1853
-102
lines changed

src/TibiaSpellsOverviewV3.go

Lines changed: 90 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,48 @@ package main
33
import (
44
"log"
55
"net/http"
6-
"regexp"
76
"strings"
87

98
"github.com/PuerkitoBio/goquery"
109
"github.com/gin-gonic/gin"
1110
)
1211

13-
var (
14-
SpellInformationRegex = regexp.MustCompile(`<td>.*spell=(.*)&amp;voc.*">(.*)<\/a> \((.*)\)<\/td><td>(.*)<\/td><td>(.*)<\/td><td>([0-9]+)<\/td><td>([0-9]+)<\/td><td>([0-9]+)<\/td><td>(.*)<\/td>`)
15-
)
12+
// Child of Spells
13+
type Spell struct {
14+
Name string `json:"name"`
15+
Spell string `json:"spell_id"`
16+
Formula string `json:"formula"`
17+
Level int `json:"level"`
18+
Mana int `json:"mana"`
19+
Price int `json:"price"`
20+
GroupAttack bool `json:"group_attack"`
21+
GroupHealing bool `json:"group_healing"`
22+
GroupSupport bool `json:"group_support"`
23+
TypeInstant bool `json:"type_instant"`
24+
TypeRune bool `json:"type_rune"`
25+
PremiumOnly bool `json:"premium_only"`
26+
}
1627

17-
// TibiaSpellsOverviewV3 func
18-
func TibiaSpellsOverviewV3(c *gin.Context) {
28+
// Child of JSONData
29+
type Spells struct {
30+
SpellsVocationFilter string `json:"spells_filter"`
31+
Spells []Spell `json:"spell_list"`
32+
}
33+
34+
//
35+
// The base includes two levels: Spells and Information
36+
type SpellsOverviewResponse struct {
37+
Spells Spells `json:"spells"`
38+
Information Information `json:"information"`
39+
}
1940

41+
func TibiaSpellsOverviewV3(c *gin.Context) {
2042
// getting params from URL
2143
vocation := c.Param("vocation")
2244
if vocation == "" {
2345
vocation = TibiadataDefaultVoc
2446
}
2547

26-
// Child of Spells
27-
type Spell struct {
28-
Name string `json:"name"`
29-
Spell string `json:"spell_id"`
30-
Formula string `json:"formula"`
31-
Level int `json:"level"`
32-
Mana int `json:"mana"`
33-
Price int `json:"price"`
34-
GroupAttack bool `json:"group_attack"`
35-
GroupHealing bool `json:"group_healing"`
36-
GroupSupport bool `json:"group_support"`
37-
TypeInstant bool `json:"type_instant"`
38-
TypeRune bool `json:"type_rune"`
39-
PremiumOnly bool `json:"premium_only"`
40-
}
41-
42-
// Child of JSONData
43-
type Spells struct {
44-
SpellsVocationFilter string `json:"spells_filter"`
45-
Spells []Spell `json:"spell_list"`
46-
}
47-
48-
//
49-
// The base includes two levels: Spells and Information
50-
type JSONData struct {
51-
Spells Spells `json:"spells"`
52-
Information Information `json:"information"`
53-
}
54-
5548
// Sanitize of vocation input
5649
vocationName, _ := TibiaDataVocationValidator(vocation)
5750
if vocationName == "all" || vocationName == "none" {
@@ -73,90 +66,88 @@ func TibiaSpellsOverviewV3(c *gin.Context) {
7366
return
7467
}
7568

69+
jsonData := TibiaSpellsOverviewV3Impl(vocationName, BoxContentHTML)
70+
71+
// return jsonData
72+
TibiaDataAPIHandleSuccessResponse(c, "TibiaSpellsOverviewV3", jsonData)
73+
}
74+
75+
// TibiaSpellsOverviewV3 func
76+
func TibiaSpellsOverviewV3Impl(vocationName string, BoxContentHTML string) SpellsOverviewResponse {
7677
// Loading HTML data into ReaderHTML for goquery with NewReader
7778
ReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(BoxContentHTML))
7879
if err != nil {
7980
log.Fatal(err)
8081
}
8182

82-
// Creating empty SpellsData var
83-
var (
84-
SpellsData []Spell
85-
GroupAttack, GroupHealing, GroupSupport, TypeInstant, TypeRune, PremiumOnly bool
86-
)
83+
var SpellsData []Spell
8784

8885
// Running query over each div
89-
ReaderHTML.Find(".TableContentContainer table tr").Each(func(index int, s *goquery.Selection) {
90-
91-
// Storing HTML into SpellDivHTML
92-
SpellDivHTML, err := s.Html()
93-
if err != nil {
94-
log.Fatal(err)
86+
ReaderHTML.Find("table.TableContent ~ table tr").Each(func(index int, s *goquery.Selection) {
87+
//Skip header row
88+
if index == 0 {
89+
return
9590
}
9691

97-
subma1 := SpellInformationRegex.FindAllStringSubmatch(SpellDivHTML, 1)
98-
99-
// check if regex return length is over 0 and the match of name is over 1
100-
if len(subma1) > 0 {
101-
// SpellGroup
102-
GroupAttack = false
103-
GroupHealing = false
104-
GroupSupport = false
105-
106-
switch subma1[0][4] {
107-
case "Attack":
108-
GroupAttack = true
109-
case "Healing":
110-
GroupHealing = true
111-
case "Support":
112-
GroupSupport = true
113-
}
114-
115-
// Type
116-
TypeInstant = false
117-
TypeRune = false
118-
119-
switch subma1[0][5] {
120-
case "Instant":
121-
TypeInstant = true
122-
case "Rune":
123-
TypeRune = true
92+
spellBuilder := Spell{}
93+
94+
s.Find("td").Each(func(index int, s2 *goquery.Selection) {
95+
selectionText := s2.Text()
96+
97+
switch index {
98+
case 0:
99+
spellBuilder.Name = selectionText
100+
spellBuilder.Spell = selectionText[0:strings.Index(selectionText, " (")]
101+
spellBuilder.Formula = selectionText[strings.Index(selectionText, " (")+2 : strings.Index(selectionText, ")")]
102+
case 1:
103+
switch selectionText {
104+
case "Attack":
105+
spellBuilder.GroupAttack = true
106+
case "Healing":
107+
spellBuilder.GroupHealing = true
108+
case "Support":
109+
spellBuilder.GroupSupport = true
110+
}
111+
case 2:
112+
switch selectionText {
113+
case "Instant":
114+
spellBuilder.TypeInstant = true
115+
case "Rune":
116+
spellBuilder.TypeRune = true
117+
}
118+
case 3:
119+
spellBuilder.Level = TibiadataStringToIntegerV3(selectionText)
120+
case 4:
121+
mana := -1
122+
if selectionText != "var." {
123+
mana = TibiadataStringToIntegerV3(selectionText)
124+
}
125+
126+
spellBuilder.Mana = mana
127+
case 5:
128+
price := 0
129+
if selectionText != "free" {
130+
price = TibiadataStringToIntegerV3(selectionText)
131+
}
132+
133+
spellBuilder.Price = price
134+
case 6:
135+
if selectionText == "yes" {
136+
spellBuilder.PremiumOnly = true
137+
}
124138
}
139+
})
125140

126-
// PremiumOnly
127-
if subma1[0][9] == "yes" {
128-
PremiumOnly = true
129-
} else {
130-
PremiumOnly = false
131-
}
132-
133-
// Creating data block to return
134-
SpellsData = append(SpellsData, Spell{
135-
Name: subma1[0][2],
136-
Spell: subma1[0][1],
137-
Formula: TibiaDataSanitizeDoubleQuoteString(TibiaDataSanitizeEscapedString(subma1[0][3])),
138-
Level: TibiadataStringToIntegerV3(subma1[0][6]),
139-
Mana: TibiadataStringToIntegerV3(subma1[0][7]),
140-
Price: TibiadataStringToIntegerV3(subma1[0][8]),
141-
GroupAttack: GroupAttack,
142-
GroupHealing: GroupHealing,
143-
GroupSupport: GroupSupport,
144-
TypeInstant: TypeInstant,
145-
TypeRune: TypeRune,
146-
PremiumOnly: PremiumOnly,
147-
})
148-
}
149-
141+
SpellsData = append(SpellsData, spellBuilder)
150142
})
151143

152144
// adding readable SpellsVocationFilter field
153145
if vocationName == "" {
154146
vocationName = "all"
155147
}
156148

157-
//
158149
// Build the data-blob
159-
jsonData := JSONData{
150+
return SpellsOverviewResponse{
160151
Spells{
161152
SpellsVocationFilter: vocationName,
162153
Spells: SpellsData,
@@ -166,7 +157,4 @@ func TibiaSpellsOverviewV3(c *gin.Context) {
166157
Timestamp: TibiadataDatetimeV3(""),
167158
},
168159
}
169-
170-
// return jsonData
171-
TibiaDataAPIHandleSuccessResponse(c, "TibiaSpellsOverviewV3", jsonData)
172160
}

src/TibiaSpellsOverviewV3_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package main
2+
3+
import (
4+
"io/ioutil"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestOverviewAll(t *testing.T) {
11+
data, err := ioutil.ReadFile("../testdata/spells/overviewall.html")
12+
if err != nil {
13+
t.Errorf("File reading error: %s", err)
14+
return
15+
}
16+
17+
spellsOverviewJson := TibiaSpellsOverviewV3Impl("", string(data))
18+
assert := assert.New(t)
19+
20+
assert.Equal(142, len(spellsOverviewJson.Spells.Spells))
21+
22+
firstSpell := spellsOverviewJson.Spells.Spells[0]
23+
assert.Equal("Animate Dead Rune (adana mort)", firstSpell.Name)
24+
assert.Equal("Animate Dead Rune", firstSpell.Spell)
25+
assert.Equal("adana mort", firstSpell.Formula)
26+
assert.Equal(27, firstSpell.Level)
27+
assert.Equal(600, firstSpell.Mana)
28+
assert.Equal(1200, firstSpell.Price)
29+
assert.False(firstSpell.GroupAttack)
30+
assert.False(firstSpell.GroupHealing)
31+
assert.True(firstSpell.GroupSupport)
32+
assert.False(firstSpell.TypeInstant)
33+
assert.True(firstSpell.TypeRune)
34+
assert.True(firstSpell.PremiumOnly)
35+
36+
findPersonSpell := spellsOverviewJson.Spells.Spells[53]
37+
assert.Equal("Find Person (exiva \"name\")", findPersonSpell.Name)
38+
assert.Equal("Find Person", findPersonSpell.Spell)
39+
assert.Equal("exiva \"name\"", findPersonSpell.Formula)
40+
assert.Equal(8, findPersonSpell.Level)
41+
assert.Equal(20, findPersonSpell.Mana)
42+
assert.Equal(80, findPersonSpell.Price)
43+
assert.False(findPersonSpell.GroupAttack)
44+
assert.False(findPersonSpell.GroupHealing)
45+
assert.True(findPersonSpell.GroupSupport)
46+
assert.True(findPersonSpell.TypeInstant)
47+
assert.False(findPersonSpell.TypeRune)
48+
assert.False(findPersonSpell.PremiumOnly)
49+
}
50+
51+
func TestOverviewDruid(t *testing.T) {
52+
data, err := ioutil.ReadFile("../testdata/spells/overviewdruid.html")
53+
if err != nil {
54+
t.Errorf("File reading error: %s", err)
55+
return
56+
}
57+
58+
spellsOverviewJson := TibiaSpellsOverviewV3Impl("druid", string(data))
59+
assert := assert.New(t)
60+
61+
assert.Equal("druid", spellsOverviewJson.Spells.SpellsVocationFilter)
62+
assert.Equal(73, len(spellsOverviewJson.Spells.Spells))
63+
}

0 commit comments

Comments
 (0)