Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

go api: fix regexp escape missing wildcard characters - #26

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 1 addition & 11 deletions backend/api/deck.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"encoding/json"
"errors"
"fmt"
"regexp"
"strings"

"github.com/gin-gonic/gin"
Expand Down Expand Up @@ -60,11 +59,6 @@ func (a *API) getDeckHandler(c *gin.Context) {
c.Data(200, "text/plain", []byte(result.String()))
}

func escapeRegexp(s string) string {
r := regexp.MustCompile(`[-\/\\^$*+?.()|[\]{}]`)
return r.ReplaceAllString(s, "\\$&")
}

func decompress(s string) (string, error) {
parts := strings.Split(s, "||")
if len(parts) < 2 {
Expand All @@ -77,11 +71,7 @@ func decompress(s string) (string, error) {
for i := len(compressionDict) - 1; i >= 0; i-- {
word := compressionDict[i]
wildCard := fmt.Sprintf("&%c", WILDCARDS[i])
r, err := regexp.Compile(escapeRegexp(wildCard))
if err != nil {
return "", err
}
text = r.ReplaceAllString(text, word)
text = strings.ReplaceAll(text, wildCard, word)
}
return text, nil
}
Expand Down
90 changes: 90 additions & 0 deletions backend/api/deck_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ package api

import (
"fmt"
"io"
"net/http/httptest"
"os"
"strings"
"sync"
"testing"

"github.com/gin-gonic/gin"
"gotest.tools/v3/assert"
)

Expand Down Expand Up @@ -91,6 +96,91 @@ func TestDecompress(t *testing.T) {
}
}

func TestDecompressIntegration(t *testing.T) {
// cases straight from mod output
testCases := []struct {
desc string
inputFile string
}{
{
desc: "Very large deck",
inputFile: "testdata/breaking-1.txt",
},
{
desc: "Another very large deck",
inputFile: "testdata/breaking-2.txt",
},
}

for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
inpFile, err := os.Open(tc.inputFile)
assert.NilError(t, err)
defer inpFile.Close()

inp, err := io.ReadAll(inpFile)
assert.NilError(t, err)

actualOutput, err := decompress(string(inp))
assert.NilError(t, err)

// should be no & symbols
assert.Equal(t, strings.Contains(actualOutput, "&"), false, actualOutput)
})
}
}

// trying to replicate JSON escape HTML issue
func TestDecompressAPIIntegration(t *testing.T) {
// cases straight from mod output
testCases := []struct {
desc string
inputFile string
}{
{
desc: "Very large deck",
inputFile: "testdata/breaking-1.txt",
},
{
desc: "Another very large deck",
inputFile: "testdata/breaking-2.txt",
},
}

apiHandler := &API{
deckLists: make(map[string]string),
deckLock: &sync.RWMutex{},
}

for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
inpFile, err := os.Open(tc.inputFile)
assert.NilError(t, err)
defer inpFile.Close()

inp, err := io.ReadAll(inpFile)
assert.NilError(t, err)

apiHandler.deckLists["test"] = string(inp)

respW := httptest.NewRecorder()
testCtx, _ := gin.CreateTestContext(respW)
testCtx.Params = gin.Params{
{Key: "name", Value: "test"},
}

apiHandler.getDeckHandler(testCtx)

assert.Equal(t, respW.Code, 200)

actualOutput := respW.Body.String()

// should be no & symbols
assert.Equal(t, strings.Contains(actualOutput, "&"), false, actualOutput)
})
}
}

func TestParseCommaDelimitedIntegerArray(t *testing.T) {
testCases := []struct {
desc string
Expand Down
1 change: 1 addition & 0 deletions backend/api/testdata/breaking-1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
damage|#yBlock|#yExhaust|Deal|your|.;;|card|cards|Gain|#yVulnerable|#yPoison|Whenever|discard|Apply|turn|this|additional|enemies|hand|pile|combat|#yLightning|Draw|gain|random|into|played|the|from|#yChannel|times|draw|#yWeak|Attack|you|enemy|start|#yRetain|increase|Energy|Double|#yEthereal|attack|Attacks|Discard|twice|each|discarded|creatures|#yScry|number|play|#yStance|Strike|#yIntangible|have|#yShivs|[E]|receive|#yDexterity|Permanently|Costs|apply|equal|first|for|ALL|Unplayable|Poison|#yStrength|next|lose|#yUpgraded|Vulnerable|#g4|#yUpgrade|unblocked|Dexterity|Put|#g2|Form|#g10|and|Strength|copy|only|#yFatal|#g7||0,1,2,2,2,3,4,4,5,6,6,7,8,9,10,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,14,14,14,15,16,17,18,19,20,21,21,21,22,23,24,25,25,26,27,28,29,29,29,30,31,32,33,34,34,34,35,35,36,37,37,38,39,40,41,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,43,44,45,46,46,46,47,48,48,48,49,50,51,52,53,54,54,54,55,56,57,58,59;;;Acrobatics;0;-;-1;-1;+;0;-;&m &* &6s. NL Dis&6 1 &6.;-;1;1;1;2;1;&m 3 &6s. NL Dis&6 1 &6&5Anger;0;-;-1;-1;+;0;-;&3 #g8 &0. NL Add a &' of &f &6 NL &p &4 dis&6 &j.;-;0;0;0;2;0;&3 6 &0. NL Add a &' of &f &6 NL &p &4 dis&6 &j&5Apo&rosis;0;-;-1;-1;+;0;0,1;&: &% &4 NL &6s &^ &r rest of NL &k. NL &2.;0,1;2;1;1;4;4;&: &% &4 NL &6s &^ &r rest of NL &k. NL &2&5Auto-Shields;0;-;-1;-1;+;0;2;If &z &V no &1, NL &n #g15 &1.;2;1;1;1;3;2;If &z &V no &1, NL &n 11 &1&5Backflip;0;-;-1;-1;+;0;2;&8 #g8 &1. NL &m 2 &6s.;2;1;1;1;2;1;&8 5 &1. NL &m 2 &6s&5Bash;0;-;-1;-1;+;0;3;&3 &# &0. NL &d #g3 &9.;3;2;2;0;0;0;&3 8 &0. NL &d 2 &9&5Blade Dance;0;-;60;60;+;0;-;Add &* &W &p &4 NL &i.;-;1;1;1;2;1;Add 3 &W &p &4 NL &i&5Bouncing Flask;0;-;-1;-1;+;0;4;&d 3 &a to a NL &o &A &* NL &v.;4;2;2;1;3;1;&d 3 &a to a NL &o &A 3 NL &v&5Clash;0;-;-1;-1;+;0;-;Can &{ be &q if NL every &6 in &4 NL &i is an &y. NL &3 #g18 &0.;-;0;0;0;2;0;Can &{ be &q if NL every &6 in &4 NL &i is an &y. NL &3 14 &0&5Cloak &$ Dagger;0;-;60;60;+;0;2;&8 6 &1. NL Add &( &W &p &4 NL &i.;2;1;1;1;2;1;&8 6 &1. NL Add 1 #yShiv &p &4 NL &i&5Com&j Driver;0;-;-1;-1;+;0;-;&3 &# &0. NL &m 1 &6 &^ &L NL unique Orb &z &V.;-;1;1;0;2;2;&3 7 &0. NL &m 1 &6 &^ &L NL unique Orb &z &V&5Consecrate;0;-;-1;-1;+;0;-;&3 #g8 &0 to &% NL &h.;-;0;0;0;2;3;&3 5 &0 to &% NL &h&5Crippling Cloud;0;-;-1;-1;+;0;4,5,1;&d &~ &a &$ 2 NL &x to &% &h. NL &2.;4,5,1;2;2;1;3;1;&d 4 &a &$ 2 NL &x to &% &h. NL &2&5Deadly &@;0;-;-1;-1;+;0;4;&d &~ &a.;4;1;1;1;2;1;&d 5 &a&5Defend;0;-;-1;-1;+;0;2;&8 #g8 &1.;2;1;1;1;0;2;&8 5 &1&5Deflect;0;-;-1;-1;+;0;2;&8 &~ &1.;2;0;0;1;2;1;&8 4 &1&5Demon &);0;-;-1;-1;+;0;6;At &r &B of &4 NL &e, &n #g3 &>.;6;3;3;2;4;0;At &r &B of &4 NL &e, &n 2 &>&5Deva &);0;-;-1;-1;+;0;8;At &r &B of &4 NL &e, &n &X NL &$ &D &f &n NL by !M!.;7,8;3;3;2;4;3;#yE&rreal. NL At &r &B of &4 NL &e, &n &X NL &$ &D &f &n NL by !M!&5&F &E;0;-;-1;-1;+;0;1;&F &4 &E. NL &2.;1;1;0;1;3;2;&F &4 &E. NL &2&5Echo &);0;-;-1;-1;+;0;-;The &/ &6 &z &Q NL &L &e is &q NL &K.;7;3;3;2;4;2;#yE&rreal. NL The &/ &6 &z &Q NL &L &e is &q NL &K&5Empty Fist;0;-;-1;-1;+;0;9;&3 #g14 &0. NL Exit &4 &R.;9;1;1;0;2;3;&3 9 &0. NL Exit &4 &R&5Endless Agony;0;-;-1;-1;+;0;1;&3 #g6 &0. NL &b &z &w NL &f &6, add a &' of NL it &p &4 &i. NL &2.;1;0;0;0;3;1;&3 4 &0. NL &b &z &w NL &f &6, add a &' of NL it &p &4 &i. NL &2&5Entrench;0;-;-1;-1;+;0;2;&F &4 &1.;2;2;1;1;3;0;&F &4 &1&5Eruption;0;-;-1;-1;+;0;10;&3 9 &0. NL Enter #yWrath.;10;2;1;0;0;3;&3 9 &0. NL Enter #yWrath&5Eviscerate;0;-;-1;-1;+;0;8;&` 1 less &X NL &^ &L &6 dis&6ed NL &f &e. NL &3 #g9 &0 3 &v.;8;3;3;0;3;1;&` 1 less &X NL &^ &L &6 dis&6ed NL &f &e. NL &3 7 &0 3 &v&5Flying Sleeves;0;-;-1;-1;+;0;11;&C. NL &3 #g6 &0 &K.;11;1;1;0;2;3;&C. NL &3 4 &0 &K&5Follow-Up;0;-;-1;-1;+;0;8;&3 #g11 &0. NL If &r last &6 &q NL &f &k was an NL &y, &n &X.;8;1;1;0;2;3;&3 7 &0. NL If &r last &6 &q NL &f &k was an NL &y, &n &X&5Genetic Algorithm;0;-;-1;-1;+;0;2,1;&8 1 &1. NL &_ &D NL &f &6's &1 by NL !M!. NL &2.;2,1;1;1;1;3;2;&8 1 &1. NL &_ &D NL &f &6's &1 by NL !M!. NL &2&5Go &^ &r Eyes;0;-;-1;-1;+;0;5;&3 &* &0. NL If &r &A intends to NL &H, &[ &( &x.;5;0;0;0;2;2;&3 3 &0. NL If &r &A intends to NL &H, &[ 1 &x&5H&$ of Greed;0;-;-1;-1;+;0;12;&3 &(5 &0. NL If &}, &n &(5 Gold.;12;2;2;0;4;4;&3 20 &0. NL If &}, &n 20 Gold&5Headbutt;0;-;-1;-1;+;0;-;&3 #g12 &0. NL &. a &6 &s &4 NL dis&6 &j on top of NL &4 &w &j.;-;1;1;0;2;0;&3 9 &0. NL &. a &6 &s &4 NL dis&6 &j on top of NL &4 &w &j&5Heatsinks;0;-;-1;-1;+;0;-;&b &z &Q a NL Power &6, &w &( NL &6s.;-;1;1;2;3;2;&b &z &Q a NL Power &6, &w 1 NL &6&5Hologram;0;-;-1;-1;+;0;2;&8 #g5 &1. NL &. a &6 &s &4 NL dis&6 &j &p &4 NL &i.;2,1;1;1;1;2;2;&8 3 &1. NL &. a &6 &s &4 NL dis&6 &j &p &4 NL &i. NL &2&5Iron Wave;0;-;-1;-1;+;0;2;&8 &~ &1. NL &3 &~ &0.;2;1;1;0;2;0;&8 5 &1. NL &3 5 &0&5Master of Strategy;0;-;-1;-1;+;0;1;&m &* &6s. NL &2.;1;0;0;1;4;4;&m 3 &6s. NL &2&5Masterful Stab;0;-;-1;-1;+;0;8;&` 1 &g &X NL &^ &L time &z &= NL HP &f &k. NL &3 #g16 &0.;8;0;0;0;3;1;&` 1 &g &X NL &^ &L time &z &= NL HP &f &k. NL &3 12 &0&5Nirvana;0;-;-1;-1;+;0;13,2;&b &z &O, NL &n &* &1.;13,2;1;1;2;3;3;&b &z &O, NL &n 3 &1&5Noxious Fumes;0;-;-1;-1;+;0;4;At &r &B of &4 NL &e, &[ #g3 &a NL to &% &h.;4;1;1;2;3;1;At &r &B of &4 NL &e, &[ 2 &a NL to &% &h&5Pommel &S;0;-;-1;-1;+;0;-;&3 &# &0. NL &m &( &6s.;-;1;1;0;2;0;&3 9 &0. NL &m 1 &6&5Protect;0;-;-1;-1;+;0;11,2;&C. NL &8 #g16 &1.;11,2;2;2;1;2;3;&C. NL &8 12 &1&5Rebound;0;-;-1;-1;+;0;-;&3 #g12 &0. NL &. &r &< &6 &z NL &Q &f &e on top of NL &4 &w &j.;-;1;1;0;2;2;&3 9 &0. NL &. &r &< &6 &z NL &Q &f &e on top of NL &4 &w &j&5Recycle;0;-;-1;-1;+;0;1,8;&2 a &6. NL &8 &X &] to its NL cost.;1,8;1;0;1;3;2;&2 a &6. NL &8 &X &] to its NL cost&5Searing Blow+2000;0;-;-1;-1;Searing Blow+2001;2000;_;&3 &(009016 &0. NL Can be &- any NL &P of &v.;0;2;2;0;3;0;&3 &(007012 &0. NL Can be &- any NL &P of &v&5Shrug It Off;0;-;-1;-1;+;0;2;&8 #g11 &1. NL &m 1 &6.;2;1;1;1;2;0;&8 8 &1. NL &m 1 &6&5Stack;0;-;-1;-1;+;0;2;&8 &1 &] to &r NL &P of &6s in NL &4 dis&6 &j +3.;2;1;1;1;2;2;&8 &1 &] to &r NL &P of &6s in NL &4 dis&6 &j&5Static Discharge;0;-;-1;-1;+;0;14,15;&b &z &Y NL &; &H NL &0, &t &( NL &l.;14,15;1;1;2;3;2;&b &z &Y NL &; &H NL &0, &t 1 NL &l&5&S;0;-;-1;-1;+;0;-;&3 #g9 &0.;-;1;1;0;0;3;&3 6 &0&5Survivor;0;-;-1;-1;+;0;2;&8 #g11 &1. NL Dis&6 1 &6.;2;1;1;1;0;1;&8 8 &1. NL Dis&6 1 &6&5Swift &S;0;-;-1;-1;+;0;-;&3 &# &0.;-;0;0;0;3;4;&3 7 &0&5Sword Boomerang;0;-;-1;-1;+;0;-;&3 3 &0 to a NL &o &A &* NL &v.;-;1;1;0;2;0;&3 3 &0 to a NL &o &A 3 NL &v&5Terror;0;-;-1;-1;+;0;3,1;&d 99 &9. NL &2.;3,1;1;0;1;3;1;&d 99 &9. NL &2&5Third Eye;0;-;-1;-1;+;0;2,13;&8 #g9 &1. NL &O !M!.;2,13;1;1;1;2;3;&8 7 &1. NL &O !M!&5Twin &S;0;-;-1;-1;+;0;-;&3 &~ &0 &K.;-;1;1;0;2;0;&3 5 &0 &K&5Uppercut;0;-;-1;-1;+;0;5,3;&3 13 &0. NL &d &( &x. NL &d &( &9.;5,3;2;2;0;3;0;&3 13 &0. NL &d 1 &x. NL &d 1 &9&5Violence;0;-;-1;-1;+;0;1;&. &* &o &ys NL &s &4 &w &j NL &p &4 &i. NL &2.;1;0;0;1;4;4;&. 3 &o &ys NL &s &4 &w &j NL &p &4 &i. NL &2&5Wheel Kick;0;-;-1;-1;+;0;-;&3 &(0 &0. NL &m 2 &6s.;-;2;2;0;3;3;&3 15 &0. NL &m 2 &6s&5Wraith &);0;-;-1;-1;+;0;16,17;&8 #g3 &T. NL At &r end of &4 NL &e, &= 1 &Z.;16,17;3;3;2;4;1;&8 2 &T. NL At &r end of &4 NL &e, &= 1 &Z&5Wreath of Flame;0;-;-1;-1;+;0;-;Your &< &y deals NL #g8 &g &0.;-;1;1;1;3;3;Your &< &y deals NL 5 &g &0&5Zap;0;-;-1;-1;+;0;14,15;&t 1 &l.;14,15;1;0;1;0;2;&t 1 &l&5Ascender's Bane;0;-;-1;-1;-;0;-;-;18,7;-2;-2;4;1;5;#yUn&Qable. NL #yE&rreal. NL Cannot be removed NL &s &4 deck&5Shiv;0;-;-1;-1;+;0;1;&3 #g6 &0. NL &2.;1;0;0;0;1;4;&3 4 &0. NL &2&5;Upgrade;Upgrading &6s makes &rm more powerful. Cards can &{ be upgraded once&5Exhaust;Removed until end of &k&5Block;Until &< &e, prevents &0&5&+;&+ &N take #b50% more &0 &s &ys&5&@;&@ed &N &= HP at &r &B of &rir &e. Each &e, &@ is reduced by #b1&5Weak;Weakened &N deal #b25% less &0 with &ys&5&!;&! adds &g &0 to &Hs&5E&rreal;If &f &6 is in &4 &i at &r end of &e, it is exhausted. Exhausted &6s are removed &s &4 deck until &r end of &k&5&X &E;&E is used to &Q &6s &s &4 &i&5Stance;You can &{ &V one stance at a time&5Wrath;In &f &R, &z deal &$ &Y double &H &0&5Retain;Retained &6s are not dis&6ed at &r end of &e&5Fatal;Triggers whenever &f &6 kills a non-minion &A&5Scry;Look at &r top X &6s of &4 &w &j. You may dis&6 any of &rm&5Channel;Channeling an Orb puts it &p &4 &/ empty slot. If &z &V no empty slots, &4 &/ Orb is automatically #yEvoked to make room&5Lightning;Orb: &3s &0 to &o &h&5Intangible;Reduce &% &0 taken &$ HP loss to #b1&5&,;&, improves Block &ned &s &6s&5Un&Qable;Un&Qable &6s cannot be &q &s &4 &i.
Loading
Loading