Skip to content
Draft
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
64 changes: 34 additions & 30 deletions spec/System/TestTradeQueryCurrency_spec.lua
Original file line number Diff line number Diff line change
@@ -1,54 +1,58 @@
describe("TradeQuery Currency Conversion", function()
local mock_tradeQuery = new("TradeQuery", { itemsTab = {} })
local mock_tradeQuery

-- test case for commit: "Skip callback on errors to prevent incomplete conversions"
describe("FetchCurrencyConversionTable", function()
-- Pass: Callback not called on error
-- Fail: Callback called, indicating partial data risk
it("skips callback on error", function()
local orig_launch = launch
local spy = { called = false }
launch = {
DownloadPage = function(url, callback, opts)
callback(nil, "test error")
end
}
mock_tradeQuery:FetchCurrencyConversionTable(function()
spy.called = true
end)
launch = orig_launch
assert.is_false(spy.called)
end)
before_each(function()
mock_tradeQuery = new("TradeQuery", { itemsTab = {} })
end)

describe("ConvertCurrencyToChaos", function()
-- Pass: Ceils amount to integer (e.g., 4.9 -> 5)
-- Fail: Wrong value or nil, indicating broken rounding/baseline logic, causing inaccurate chaos totals
describe("ConvertCurrencyToDivs", function()
-- Pass: Calculates price in divs
-- Fail: Wrong value or nil, indicating broken rounding/baseline logic
it("handles chaos currency", function()
mock_tradeQuery.pbCurrencyConversion = { league = { chaos = 1 } }
mock_tradeQuery.pbCurrencyConversion = { league = { chaos = 0.1 } }
mock_tradeQuery.pbLeague = "league"
local result = mock_tradeQuery:ConvertCurrencyToChaos("chaos", 4.9)
assert.are.equal(result, 5)
local result = mock_tradeQuery:ConvertCurrencyToDivs("chaos", 5)
assert.are.equal(result, 0.5)
end)

-- Pass: Returns nil without crash
-- Fail: Crashes or wrong value, indicating unhandled currencies, corrupting price conversions
it("returns nil for unmapped", function()
local result = mock_tradeQuery:ConvertCurrencyToChaos("exotic", 10)
local result = mock_tradeQuery:ConvertCurrencyToDivs("exotic", 10)
assert.is_nil(result)
end)
end)

describe("PriceBuilderProcessPoENinjaResponse", function()
-- Pass: Processes without error, restoring map
-- Pass: Processes without error, restoring map while adding a notice
-- Fail: Corrupts map or crashes, indicating fragile API response handling, breaking future conversions
it("handles unmapped currency", function()
it("handles empty response", function()
local orig_conv = mock_tradeQuery.currencyConversionTradeMap
mock_tradeQuery.currencyConversionTradeMap = { div = "id" }
local resp = { exotic = 10 }
mock_tradeQuery:PriceBuilderProcessPoENinjaResponse(resp)
mock_tradeQuery.pbLeague = "league"
mock_tradeQuery.pbCurrencyConversion = { league = {} }
mock_tradeQuery.controls.pbNotice = { label = "" }
local resp = { lines = { }}
mock_tradeQuery:PriceBuilderProcessPoENinjaResponse(resp.lines)
-- No crash expected
assert.is_true(true)
assert.is_true(mock_tradeQuery.controls.pbNotice.label == "No currencies received from PoE Ninja")
mock_tradeQuery.currencyConversionTradeMap = orig_conv
end)

-- Pass: Processes without error, restoring map while adding a notice
-- Fail: Corrupts map or crashes, indicating fragile API response handling, breaking future conversions
it("handles empty response", function()
local orig_conv = mock_tradeQuery.currencyConversionTradeMap
mock_tradeQuery.currencyConversionTradeMap = { div = "id" }
mock_tradeQuery.pbLeague = "league"
mock_tradeQuery.pbCurrencyConversion = { league = {} }
mock_tradeQuery.controls.pbNotice = { label = "" }
local resp = { lines = { { malformedLine = "lol"} }}
mock_tradeQuery:PriceBuilderProcessPoENinjaResponse(resp.lines)
-- No crash expected
assert.is_true(true)
assert.is_true(mock_tradeQuery.controls.pbNotice.label == "Currencies not updated: malformed PoE Ninja response")
mock_tradeQuery.currencyConversionTradeMap = orig_conv
end)
end)
Expand Down
69 changes: 38 additions & 31 deletions src/Classes/ImportTab.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ local ImportTabClass = newClass("ImportTab", "ControlHost", "Control", function(
self.Control()

self.build = build
self.api = new("PoEAPI", main.lastToken, main.lastRefreshToken, main.tokenExpiry)
if not main.api then
main.api = new("PoEAPI", main.lastToken, main.lastRefreshToken, main.tokenExpiry)
end


self.charImportMode = "AUTHENTICATION"
self.charImportStatus = colorCodes.WARNING.."Not authenticated"
Expand All @@ -31,32 +34,32 @@ local ImportTabClass = newClass("ImportTab", "ControlHost", "Control", function(

self.controls.logoutApiButton = new("ButtonControl", {"TOPLEFT",self.controls.charImportStatusLabel,"TOPRIGHT"}, {4, 0, 180, 16}, "^7Logout from Path of Exile API", function()
main.lastToken = nil
self.api.authToken = nil
main.api.authToken = nil
main.lastRefreshToken = nil
self.api.refreshToken = nil
main.api.refreshToken = nil
main.tokenExpiry = nil
self.api.tokenExpiry = nil
main.api.tokenExpiry = nil
main:SaveSettings()
self.charImportMode = "AUTHENTICATION"
self.charImportStatus = colorCodes.WARNING.."Not authenticated"
end)
self.controls.logoutApiButton.shown = function()
return (self.charImportMode == "SELECTCHAR" or self.charImportMode == "GETACCOUNTNAME") and self.api.authToken ~= nil
return (self.charImportMode == "SELECTCHAR" or self.charImportMode == "GETACCOUNTNAME") and main.api.authToken ~= nil
end

self.controls.characterImportAnchor = new("Control", {"TOPLEFT",self.controls.sectionCharImport,"TOPLEFT"}, {6, 40, 200, 16})
self.controls.sectionCharImport.height = function() return self.charImportMode == "AUTHENTICATION" and 60 or 200 end

-- Stage: Authenticate
self.controls.authenticateButton = new("ButtonControl", {"TOPLEFT",self.controls.characterImportAnchor,"TOPLEFT"}, {0, 0, 200, 16}, "^7Authorize with Path of Exile", function()
self.api:FetchAuthToken(function()
if self.api.authToken then
main.api:FetchAuthToken(function()
if main.api.authToken then
self.charImportMode = "GETACCOUNTNAME"
self.charImportStatus = "Authenticated"

main.lastToken = self.api.authToken
main.lastRefreshToken = self.api.refreshToken
main.tokenExpiry = self.api.tokenExpiry
main.lastToken = main.api.authToken
main.lastRefreshToken = main.api.refreshToken
main.tokenExpiry = main.api.tokenExpiry
main:SaveSettings()
self:DownloadCharacterList()
else
Expand Down Expand Up @@ -332,26 +335,30 @@ local ImportTabClass = newClass("ImportTab", "ControlHost", "Control", function(
end

-- validate the status of the api the first time
self.api:ValidateAuth(function(valid, updateSettings)
if valid then
if self.charImportMode == "AUTHENTICATION" then
self.charImportMode = "GETACCOUNTNAME"
self.charImportStatus = "Authenticated"
end
if updateSettings then
self:SaveApiSettings()
end
else
self.charImportMode = "AUTHENTICATION"
self.charImportStatus = colorCodes.WARNING.."Not authenticated"
end
end)
self:RefreshAuthStatus()
end)

function ImportTabClass:RefreshAuthStatus()
main.api:ValidateAuth(function(valid, updateSettings)
if valid then
if self.charImportMode == "AUTHENTICATION" then
self.charImportMode = "GETACCOUNTNAME"
self.charImportStatus = "Authenticated"
end
if updateSettings then
self:SaveApiSettings()
end
else
self.charImportMode = "AUTHENTICATION"
self.charImportStatus = colorCodes.WARNING.."Not authenticated"
end
end)
end

function ImportTabClass:SaveApiSettings()
main.lastToken = self.api.authToken
main.lastRefreshToken = self.api.refreshToken
main.tokenExpiry = self.api.tokenExpiry
main.lastToken = main.api.authToken
main.lastRefreshToken = main.api.refreshToken
main.tokenExpiry = main.api.tokenExpiry
main:SaveSettings()
end

Expand Down Expand Up @@ -405,11 +412,11 @@ function ImportTabClass:DownloadCharacterList()
self.charImportMode = "DOWNLOADCHARLIST"
self.charImportStatus = "Retrieving character list..."
local realm = realmList[self.controls.accountRealm.selIndex]
self.api:DownloadCharacterList(realm.realmCode, function(body, errMsg, updateSettings)
main.api:DownloadCharacterList(realm.realmCode, function(body, errMsg, updateSettings)
if updateSettings then
self:SaveApiSettings()
end
if errMsg == self.api.ERROR_NO_AUTH then
if errMsg == main.api.ERROR_NO_AUTH then
self.charImportMode = "AUTHENTICATION"
self.charImportStatus = colorCodes.WARNING.."Not authenticated"
return
Expand Down Expand Up @@ -530,13 +537,13 @@ function ImportTabClass:DownloadCharacter(callback)
local realm = realmList[self.controls.accountRealm.selIndex]
local charSelect = self.controls.charSelect
local charData = charSelect.list[charSelect.selIndex].char
self.api:DownloadCharacter(realm.realmCode, charData.name, function(body, errMsg, updateSettings)
main.api:DownloadCharacter(realm.realmCode, charData.name, function(body, errMsg, updateSettings)
self.charImportMode = "SELECTCHAR"
if updateSettings then
self:SaveApiSettings()
end
if errMsg then
if errMsg == self.api.ERROR_NO_AUTH then
if errMsg == main.api.ERROR_NO_AUTH then
self.charImportMode = "AUTHENTICATION"
self.charImportStatus = colorCodes.WARNING.."Not authenticated"
return
Expand Down
Loading