From 54447774d161f114e52785d863feef49b492c32a Mon Sep 17 00:00:00 2001 From: James Read Date: Sat, 12 Jul 2025 23:02:50 +0100 Subject: [PATCH] fix: #616 - JSON parsing of ints to float64 (#617) --- .../config.yaml | 9 ++++ .../entities/data.json | 5 ++ integration-tests/lib/elements.js | 16 +++++++ .../entityFilesWithLongIntsUseStandardForm.js | 46 +++++++++++++++++++ service/Makefile | 6 ++- service/internal/entityfiles/entityfiles.go | 12 +++++ .../internal/entityfiles/entityfiles_test.go | 17 +++++++ .../entityfiles/testdata/object-per-line.json | 5 ++ 8 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 integration-tests/configs/entityFilesWithLongIntsUseStandardForm/config.yaml create mode 100644 integration-tests/configs/entityFilesWithLongIntsUseStandardForm/entities/data.json create mode 100644 integration-tests/test/entityFilesWithLongIntsUseStandardForm.js create mode 100644 service/internal/entityfiles/entityfiles_test.go create mode 100644 service/internal/entityfiles/testdata/object-per-line.json diff --git a/integration-tests/configs/entityFilesWithLongIntsUseStandardForm/config.yaml b/integration-tests/configs/entityFilesWithLongIntsUseStandardForm/config.yaml new file mode 100644 index 0000000..9f376c7 --- /dev/null +++ b/integration-tests/configs/entityFilesWithLongIntsUseStandardForm/config.yaml @@ -0,0 +1,9 @@ +actions: + - title: 'Test me {{ test_me.name }}' + popupOnStart: execution-dialog-stdout-only + entity: testrows + shell: echo "{{ test_me.val }}" + +entities: + - name: testrows + file: entities/data.json diff --git a/integration-tests/configs/entityFilesWithLongIntsUseStandardForm/entities/data.json b/integration-tests/configs/entityFilesWithLongIntsUseStandardForm/entities/data.json new file mode 100644 index 0000000..fc3ec4b --- /dev/null +++ b/integration-tests/configs/entityFilesWithLongIntsUseStandardForm/entities/data.json @@ -0,0 +1,5 @@ +{"name":"INT with 10 numbers","val":1234567890} +{"name":"INT with 6 numbers","val":123456} +{"name":"INT with 7 numbers","val":1234567} +{"name":"FLOAT with 6 numbers","val":1.234567} +{"name":"FLOAT with 10 numbers","val":1.234567890} diff --git a/integration-tests/lib/elements.js b/integration-tests/lib/elements.js index 705cbcc..2073d7a 100644 --- a/integration-tests/lib/elements.js +++ b/integration-tests/lib/elements.js @@ -11,6 +11,22 @@ export async function getActionButtons (dashboardTitle = null) { } } +export async function getExecutionDialogOutput() { + await webdriver.wait(new Condition('Dialog with long int is visible', async () => { + const dialog = await webdriver.findElement({ id: 'execution-results-popup' }) + return await dialog.isDisplayed() + })); + + const ret = await webdriver.executeScript('return window.logEntries.get(window.executionDialog.executionTrackingId).output') + + return ret +} + +export async function closeExecutionDialog() { + const btnClose = await webdriver.findElements(By.css('[title="Close"]')) + await btnClose[0].click() +} + export function takeScreenshotOnFailure (test, webdriver) { if (test.state === 'failed') { const title = test.fullTitle(); diff --git a/integration-tests/test/entityFilesWithLongIntsUseStandardForm.js b/integration-tests/test/entityFilesWithLongIntsUseStandardForm.js new file mode 100644 index 0000000..4987c0b --- /dev/null +++ b/integration-tests/test/entityFilesWithLongIntsUseStandardForm.js @@ -0,0 +1,46 @@ +// Issue: https://github.com/OliveTin/OliveTin/issues/616 +import { describe, it, before, after } from 'mocha' +import { expect } from 'chai' +import { + getRootAndWait, + getActionButtons, + closeExecutionDialog, + takeScreenshotOnFailure, + getExecutionDialogOutput, +} from '../lib/elements.js' + +describe('config: entities', function () { + before(async function () { + await runner.start('entityFilesWithLongIntsUseStandardForm') + }) + + after(async () => { + await runner.stop() + }) + + afterEach(function () { + takeScreenshotOnFailure(this.currentTest, webdriver); + }); + + it('Entity buttons are rendered', async function() { + await getRootAndWait() + + const buttons = await getActionButtons() + + expect(buttons).to.not.be.null + expect(buttons).to.have.length(5) + + const buttonInt10 = await buttons[2] + expect(await buttonInt10.getAttribute('title')).to.be.equal('Test me INT with 10 numbers') + await buttonInt10.click() + expect(await getExecutionDialogOutput()).to.be.equal('1234567890\n', 'Expected output to be an int') + + await closeExecutionDialog() + + const buttonFloat10 = await buttons[0] + expect(await buttonFloat10.getAttribute('title')).to.be.equal('Test me FLOAT with 10 numbers') + await buttonFloat10.click() + expect(await getExecutionDialogOutput()).to.be.equal('1.234568\n', 'Expected output to be a float') + + }); +}); diff --git a/service/Makefile b/service/Makefile index b13f6cc..4f50037 100644 --- a/service/Makefile +++ b/service/Makefile @@ -26,7 +26,7 @@ compile-x64-win: compile: compile-armhf compile-x64-lin compile-x64-win -codestyle: +codestyle: go-tools go fmt ./... go vet ./... gocyclo -over 4 internal @@ -39,6 +39,10 @@ unittests: go tool cover -html=reports/unittests.out -o reports/unittests.html go-tools: + go install "github.com/fzipp/gocyclo/cmd/gocyclo" + go install "github.com/go-critic/go-critic/cmd/gocritic" + +go-tools-all: go install "github.com/bufbuild/buf/cmd/buf" go install "github.com/fzipp/gocyclo/cmd/gocyclo" go install "github.com/go-critic/go-critic/cmd/gocritic" diff --git a/service/internal/entityfiles/entityfiles.go b/service/internal/entityfiles/entityfiles.go index fecc381..5306601 100644 --- a/service/internal/entityfiles/entityfiles.go +++ b/service/internal/entityfiles/entityfiles.go @@ -12,6 +12,7 @@ import ( "os" "path/filepath" "strings" + "math" ) var ( @@ -142,11 +143,22 @@ func serializeValueToSv(prefix string, value interface{}) { serializeMapToSv(prefix, m) } else if s, ok := value.([]interface{}); ok { // if value is a slice we need to flatten it serializeSliceToSv(prefix, s) + } else if f, ok := value.(float64); ok { + if canConvertToInt64(f) { + s := int64(f) + sv.Set(prefix, fmt.Sprintf("%d", s)) + } else { + sv.Set(prefix, fmt.Sprintf("%f", f)) + } } else { sv.Set(prefix, fmt.Sprintf("%v", value)) } } +func canConvertToInt64(f float64) bool { + return f >= math.MinInt64 && f <= math.MaxInt64 && f == math.Trunc(f) +} + func serializeMapToSv(prefix string, m map[string]interface{}) { for k, v := range m { serializeValueToSv(prefix+"."+k, v) diff --git a/service/internal/entityfiles/entityfiles_test.go b/service/internal/entityfiles/entityfiles_test.go new file mode 100644 index 0000000..3de9480 --- /dev/null +++ b/service/internal/entityfiles/entityfiles_test.go @@ -0,0 +1,17 @@ +package entityfiles + +import ( + "testing" + "github.com/stretchr/testify/assert" + sv "github.com/OliveTin/OliveTin/internal/stringvariables" +) + +func TestLoadObjectPerLineJsonFile(t *testing.T) { + filename := "testdata/object-per-line.json" + + assert.Equal(t, "", sv.Get("entities.testrow.0.val"), "Value should match expected value") + + loadEntityFileJson(filename, "testrow") + + assert.Equal(t, "1234567890", sv.Get("entities.testrow.0.val"), "Value should match expected value") +} diff --git a/service/internal/entityfiles/testdata/object-per-line.json b/service/internal/entityfiles/testdata/object-per-line.json new file mode 100644 index 0000000..fc3ec4b --- /dev/null +++ b/service/internal/entityfiles/testdata/object-per-line.json @@ -0,0 +1,5 @@ +{"name":"INT with 10 numbers","val":1234567890} +{"name":"INT with 6 numbers","val":123456} +{"name":"INT with 7 numbers","val":1234567} +{"name":"FLOAT with 6 numbers","val":1.234567} +{"name":"FLOAT with 10 numbers","val":1.234567890}