236 lines
7.5 KiB
Go
236 lines
7.5 KiB
Go
package world_test
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"sort"
|
|
"testing"
|
|
|
|
"github.com/inkyblackness/hacked/ss1/resource"
|
|
"github.com/inkyblackness/hacked/ss1/world"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
type ModSuite struct {
|
|
suite.Suite
|
|
mod *world.Mod
|
|
|
|
selector *resource.Selector
|
|
|
|
lastModifiedIDs []resource.ID
|
|
lastFailedIDs []resource.ID
|
|
}
|
|
|
|
func TestModSuite(t *testing.T) {
|
|
suite.Run(t, new(ModSuite))
|
|
}
|
|
|
|
func (suite *ModSuite) SetupTest() {
|
|
suite.mod = world.NewMod(suite.onResourcesModified, func() {})
|
|
|
|
suite.selector = nil
|
|
|
|
suite.lastModifiedIDs = nil
|
|
suite.lastFailedIDs = nil
|
|
}
|
|
|
|
func (suite *ModSuite) onResourcesModified(modifiedIDs []resource.ID, failedIDs []resource.ID) {
|
|
suite.lastModifiedIDs = modifiedIDs
|
|
suite.lastFailedIDs = failedIDs
|
|
}
|
|
|
|
func (suite *ModSuite) TestResourcesCanBeRetrievedFromTheWorld() {
|
|
suite.givenWorldHas(
|
|
suite.someLocalizedResources(resource.LangAny,
|
|
suite.storing(0x0800, [][]byte{{0xAA}})))
|
|
suite.whenResourcesAreQueriedFor(resource.LangAny)
|
|
suite.thenResourcesCanBeSelected(0x0800)
|
|
}
|
|
|
|
func (suite *ModSuite) TestResourcesCanBeModified() {
|
|
suite.givenWorldHas(
|
|
suite.someLocalizedResources(resource.LangAny,
|
|
suite.storing(0x0800, [][]byte{{0xAA}})))
|
|
suite.whenModifyingBy(func(modder world.Modder) {
|
|
modder.SetResourceBlock(resource.LangAny, 0x0800, 0, []byte{0xBB})
|
|
})
|
|
suite.thenResourceBlockShouldBe(resource.LangAny, 0x0800, 0, []byte{0xBB})
|
|
}
|
|
|
|
func (suite *ModSuite) TestResourcesCanBeExtended() {
|
|
suite.givenWorldHas(
|
|
suite.someLocalizedResources(resource.LangAny,
|
|
suite.storing(0x0800, [][]byte{{0xAA}})))
|
|
suite.whenModifyingBy(func(modder world.Modder) {
|
|
modder.SetResourceBlock(resource.LangAny, 0x0800, 2, []byte{0xBB})
|
|
})
|
|
suite.thenResourceBlockShouldBe(resource.LangAny, 0x0800, 2, []byte{0xBB})
|
|
}
|
|
|
|
func (suite *ModSuite) TestResourcesCanBeRemoved() {
|
|
suite.givenWorldHas(
|
|
suite.someLocalizedResources(resource.LangAny,
|
|
suite.storing(0x0800, [][]byte{{0xAA}})))
|
|
suite.givenModifiedBy(func(modder world.Modder) {
|
|
modder.SetResourceBlock(resource.LangAny, 0x0800, 0, []byte{0xBB})
|
|
})
|
|
suite.whenModifyingBy(func(modder world.Modder) {
|
|
modder.DelResource(resource.LangAny, 0x0800)
|
|
})
|
|
suite.thenResourceBlockShouldBe(resource.LangAny, 0x0800, 0, []byte{0xAA})
|
|
}
|
|
|
|
func (suite *ModSuite) TestAdditionsAreNotified() {
|
|
suite.givenWorldHas(
|
|
suite.someLocalizedResources(resource.LangAny,
|
|
suite.storing(0x0800, [][]byte{{0xAA}})))
|
|
suite.whenModifyingBy(func(modder world.Modder) {
|
|
modder.SetResourceBlock(resource.LangAny, 0x0800, 2, []byte{0xBB})
|
|
})
|
|
suite.thenModifiedResourcesShouldBe(0x0800)
|
|
}
|
|
|
|
func (suite *ModSuite) TestModificationsToIdenticalDataAreNotNotified() {
|
|
suite.givenWorldHas(
|
|
suite.someLocalizedResources(resource.LangAny,
|
|
suite.storing(0x004C, [][]byte{{0xAA}})))
|
|
suite.whenModifyingBy(func(modder world.Modder) {
|
|
modder.SetResourceBlock(resource.LangAny, 0x004C, 0, []byte{0xAA})
|
|
})
|
|
suite.thenModifiedResourcesShouldBe()
|
|
}
|
|
|
|
func (suite *ModSuite) TestDeletionIsNotified() {
|
|
suite.givenWorldHas(
|
|
suite.someLocalizedResources(resource.LangAny,
|
|
suite.storing(0x0800, [][]byte{{0xAA}})))
|
|
suite.givenModifiedBy(func(modder world.Modder) {
|
|
modder.SetResourceBlock(resource.LangAny, 0x0800, 0, []byte{0xBB})
|
|
})
|
|
suite.whenModifyingBy(func(modder world.Modder) {
|
|
modder.DelResource(resource.LangAny, 0x0800)
|
|
})
|
|
suite.thenModifiedResourcesShouldBe(0x0800)
|
|
}
|
|
|
|
func (suite *ModSuite) TestModifiedResourceCanBeRetrieved() {
|
|
suite.whenModifyingBy(func(modder world.Modder) {
|
|
modder.SetResourceBlock(resource.LangAny, 0x0800, 0, []byte{0xBB})
|
|
modder.SetResourceBlock(resource.LangAny, 0x0800, 1, []byte{0xCC})
|
|
})
|
|
|
|
res := suite.mod.ModifiedResource(resource.LangAny, 0x0800)
|
|
require.NotNil(suite.T(), res, "Resource expected")
|
|
assert.Equal(suite.T(), 2, res.BlockCount(), "Two blocks expected")
|
|
}
|
|
|
|
func (suite *ModSuite) TestModifiedBlocksCanBeRetrievedSingle() {
|
|
suite.whenModifyingBy(func(modder world.Modder) {
|
|
modder.SetResourceBlock(resource.LangAny, 0x0800, 0, []byte{0xBB})
|
|
modder.SetResourceBlock(resource.LangAny, 0x0800, 1, []byte{0xCC})
|
|
})
|
|
|
|
assert.Equal(suite.T(), []byte{0xBB}, suite.mod.ModifiedBlock(resource.LangAny, 0x0800, 0))
|
|
assert.Equal(suite.T(), []byte{0xCC}, suite.mod.ModifiedBlock(resource.LangAny, 0x0800, 1))
|
|
}
|
|
|
|
func (suite *ModSuite) TestModifiedBlocksCanBeRetrievedBulk() {
|
|
suite.whenModifyingBy(func(modder world.Modder) {
|
|
modder.SetResourceBlock(resource.LangAny, 0x0800, 0, []byte{0xBB})
|
|
modder.SetResourceBlock(resource.LangAny, 0x0800, 1, []byte{0xCC})
|
|
})
|
|
|
|
assert.Equal(suite.T(), [][]byte{{0xBB}, {0xCC}}, suite.mod.ModifiedBlocks(resource.LangAny, 0x0800))
|
|
}
|
|
|
|
func (suite *ModSuite) givenWorldHas(res ...resource.LocalizedResources) {
|
|
suite.whenWorldIsExtendedWith(res...)
|
|
suite.lastModifiedIDs = nil
|
|
suite.lastFailedIDs = nil
|
|
}
|
|
|
|
func (suite *ModSuite) whenWorldIsExtendedWith(res ...resource.LocalizedResources) {
|
|
manifest := suite.mod.World()
|
|
at := manifest.EntryCount()
|
|
id := fmt.Sprintf("entry-%d", at)
|
|
err := suite.mod.World().InsertEntry(at, suite.anEntryWithResources(id, res...))
|
|
require.Nil(suite.T(), err, fmt.Sprintf("No error expected inserting entry at %d", at))
|
|
}
|
|
|
|
func (suite *ModSuite) whenResourcesAreQueriedFor(lang resource.Language) {
|
|
selector := suite.mod.LocalizedResources(lang)
|
|
suite.selector = &selector
|
|
}
|
|
|
|
func (suite *ModSuite) givenModifiedBy(modifier func(world.Modder)) {
|
|
suite.mod.Modify(modifier)
|
|
|
|
suite.lastModifiedIDs = nil
|
|
suite.lastFailedIDs = nil
|
|
}
|
|
|
|
func (suite *ModSuite) whenModifyingBy(modifier func(world.Modder)) {
|
|
suite.mod.Modify(modifier)
|
|
}
|
|
|
|
func (suite *ModSuite) thenResourceBlockShouldBe(lang resource.Language, id int, blockIndex int, expected []byte) {
|
|
view, viewErr := suite.mod.LocalizedResources(lang).Select(resource.ID(id))
|
|
require.Nil(suite.T(), viewErr, "No error expected selecting resource")
|
|
reader, blockErr := view.Block(blockIndex)
|
|
require.Nil(suite.T(), blockErr, "No error expected retrieving block")
|
|
data, dataErr := ioutil.ReadAll(reader)
|
|
require.Nil(suite.T(), dataErr, "No error expected reading data")
|
|
assert.Equal(suite.T(), expected, data, "Data mismatch in block")
|
|
}
|
|
|
|
func (suite *ModSuite) thenResourcesCanBeSelected(id int) {
|
|
view, err := suite.selector.Select(resource.ID(id))
|
|
assert.Nil(suite.T(), err, "No error expected")
|
|
assert.NotNil(suite.T(), view, "View expected")
|
|
}
|
|
|
|
func (suite *ModSuite) thenModifiedResourcesShouldBe(expected ...int) {
|
|
identified := make([]resource.ID, len(expected))
|
|
for index, id := range expected {
|
|
identified[index] = resource.ID(id)
|
|
}
|
|
suite.sortIDs(identified)
|
|
suite.sortIDs(suite.lastModifiedIDs)
|
|
|
|
assert.Equal(suite.T(), identified, suite.lastModifiedIDs, "Modified IDs don't match")
|
|
}
|
|
|
|
func (suite *ModSuite) sortIDs(ids []resource.ID) {
|
|
sort.Slice(ids, func(a, b int) bool { return ids[a] < ids[b] })
|
|
}
|
|
|
|
func (suite *ModSuite) someLocalizedResources(lang resource.Language, modifiers ...func(*resource.Store)) resource.LocalizedResources {
|
|
var store resource.Store
|
|
for _, modifier := range modifiers {
|
|
modifier(&store)
|
|
}
|
|
return resource.LocalizedResources{
|
|
ID: "unnamed",
|
|
Language: lang,
|
|
Viewer: store,
|
|
}
|
|
}
|
|
|
|
func (suite *ModSuite) anEntryWithResources(id string, res ...resource.LocalizedResources) *world.ManifestEntry {
|
|
return &world.ManifestEntry{
|
|
ID: id,
|
|
Resources: res,
|
|
}
|
|
}
|
|
|
|
func (suite *ModSuite) storing(id int, data [][]byte) func(*resource.Store) {
|
|
return func(store *resource.Store) {
|
|
_ = store.Put(resource.ID(id), resource.Resource{
|
|
Blocks: resource.BlocksFrom(data),
|
|
})
|
|
}
|
|
}
|