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

Bug/3900/flipping delta maps #3903

Merged
merged 7 commits into from
Feb 3, 2025
Merged
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
1 change: 1 addition & 0 deletions visualization/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/)
- Fix applying Custom Views [#3898](https://github.com/MaibornWolff/codecharta/pull/3898)
- The camera is now only reset when the area or the height of the map is changed [#3896](https://github.com/MaibornWolff/codecharta/pull/3896)
- Fix freezing app on uploading already loaded files [#3901](https://github.com/MaibornWolff/codecharta/pull/3901)
- Fix switching maps in delta view [#3903](https://github.com/MaibornWolff/codecharta/pull/3903)

## [1.131.2] - 2024-12-04

Expand Down
Original file line number Diff line number Diff line change
@@ -1,88 +1,134 @@
import { FileSelectionState, FileState } from "../../../model/files/files"
import { FILE_META, TEST_FILE_DATA } from "../../../util/dataMocks"
import { FILE_META, TEST_FILE_DATA, TEST_FILE_DATA_JAVA, TEST_FILE_DATA_TWO } from "../../../util/dataMocks"
import { MockStore, provideMockStore } from "@ngrx/store/testing"
import { TestBed } from "@angular/core/testing"
import { onlyVisibleFilesMatterComparer, visibleFileStatesSelector } from "./visibleFileStates.selector"
import { _onlyVisibleFilesMatterComparer, visibleFileStatesSelector } from "./visibleFileStates.selector"

describe("_onlyVisibleFilesMatterComparer", () => {
it("should return true for two empty file state arrays", () => {
expect(onlyVisibleFilesMatterComparer([], [])).toBe(true)
describe("_onlyVisibleFilesMatterComparer with standard state", () => {
const fileStatePartial1 = { selectedAs: FileSelectionState.Partial, file: TEST_FILE_DATA }
const fileStatePartial2 = { selectedAs: FileSelectionState.Partial, file: TEST_FILE_DATA_TWO }
const fileStateNone = { selectedAs: FileSelectionState.None, file: TEST_FILE_DATA_JAVA }

it("should return true for two empty file states", () => {
expect(_onlyVisibleFilesMatterComparer([], [])).toBe(true)
})

it("should return true for the same file states", () => {
const fileStates = [fileStatePartial1, fileStateNone]
expect(_onlyVisibleFilesMatterComparer(fileStates, fileStates)).toBe(true)
})

it("should return false for file states with different number of visible files", () => {
const fileStates1 = [fileStatePartial1, fileStatePartial2]
const fileStates2 = [fileStatePartial1, fileStateNone]
expect(_onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(false)
})

it("should return false for arrays of different lengths", () => {
const fileStates1 = [{ selectedAs: FileSelectionState.Reference, file: TEST_FILE_DATA }]
it("should return false for file states with different visible files", () => {
const fileStates1 = [fileStatePartial1]
const fileStates2 = [fileStatePartial2]
expect(_onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(false)
})

it("should return true for file states with same visible files in different order", () => {
const fileStates1 = [fileStatePartial1, fileStatePartial2]
const fileStates2 = [fileStatePartial2, fileStatePartial1]
expect(_onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(true)
})
})

describe("_onlyVisibleFilesMatterComparer with delta state", () => {
const fileStateReference = { selectedAs: FileSelectionState.Reference, file: TEST_FILE_DATA }
const fileStateComparison = { selectedAs: FileSelectionState.Comparison, file: TEST_FILE_DATA_TWO }
const fileStateNone = { selectedAs: FileSelectionState.None, file: TEST_FILE_DATA_JAVA }

it("should return false for states of different lengths", () => {
const fileStates1 = [fileStateReference]
const fileStates2 = []
expect(onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(false)
})

it("should return true for arrays with the same visible file checksums, in the same order", () => {
const file1 = { selectedAs: FileSelectionState.Reference, file: TEST_FILE_DATA }

const fileStates1: FileState[] = [
file1,
{
selectedAs: FileSelectionState.None,
file: {
...TEST_FILE_DATA,
fileMeta: { ...FILE_META, fileName: "second-file" }
}
}
]
const fileStates2 = [file1]
expect(onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(true)
})

it("should return true for arrays with the same visible files in different orders", () => {
const fileStates1: FileState[] = [
{ selectedAs: FileSelectionState.Reference, file: TEST_FILE_DATA },
{
selectedAs: FileSelectionState.None,
file: {
...TEST_FILE_DATA,
fileMeta: { ...FILE_META, fileName: "second-file" }
}
}
]
const fileStates2 = [
{
selectedAs: FileSelectionState.None,
file: {
...TEST_FILE_DATA,
fileMeta: { ...FILE_META, fileName: "second-file" }
}
},
{ selectedAs: FileSelectionState.Reference, file: TEST_FILE_DATA }
]
expect(onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(true)
})

it("should return false for arrays with different visible file checksums", () => {
const fileStates1: FileState[] = [{ selectedAs: FileSelectionState.Reference, file: TEST_FILE_DATA }]
const fileStates2 = [
{
selectedAs: FileSelectionState.Reference,
file: {
...TEST_FILE_DATA,
fileMeta: { ...FILE_META, fileName: "second-file" }
}
}
]
expect(onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(false)
})

it("should return false for arrays of different file selection states", () => {
const fileStates1 = [{ selectedAs: FileSelectionState.Reference, file: TEST_FILE_DATA }]
const fileStates2 = [
{
selectedAs: FileSelectionState.Partial,
file: {
...TEST_FILE_DATA,
fileMeta: { ...FILE_META, fileName: "second-file" }
}
},
{ selectedAs: FileSelectionState.Partial, file: TEST_FILE_DATA }
]
expect(onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(false)
expect(_onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(false)
})

it("should return true for states with the same visible files", () => {
const fileStates1: FileState[] = [fileStateReference, fileStateNone]
const fileStates2 = [fileStateReference]

expect(_onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(true)
})

it("should return false for states with no reference file", () => {
const fileStates1: FileState[] = [fileStateReference, fileStateNone]
const fileStates2 = [fileStateNone]

expect(_onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(false)
})

it("should return false for states with no comparison file", () => {
const fileStates1: FileState[] = [fileStateReference, fileStateComparison]
const fileStates2 = [fileStateReference, fileStateNone]

expect(_onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(false)
})

it("should return true for states with the same visible files in different orders", () => {
const fileStates1: FileState[] = [fileStateReference, fileStateNone]
const fileStates2 = [fileStateNone, fileStateReference]
expect(_onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(true)
})

it("should return false for states with different visible files", () => {
const fileStates1: FileState[] = [fileStateReference]
const fileStates2 = [fileStateNone]

expect(_onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(false)
})

it("should return false for states of different file selection states", () => {
const fileStates1: FileState[] = [fileStateReference]
const fileStates2 = [{ ...fileStateReference, selectedAs: FileSelectionState.Comparison }]
expect(_onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(false)
})

it("should return true when both states have the same reference and comparison files correctly set", () => {
const referenceFile: FileState = fileStateReference
const comparisonFile: FileState = { ...fileStateNone, selectedAs: FileSelectionState.Comparison }

const fileStates1 = [referenceFile, comparisonFile]
const fileStates2 = [referenceFile, comparisonFile]

expect(_onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(true)
})

it("should return false for different comparison files", () => {
const referenceFile1: FileState = fileStateReference
const referenceFile2: FileState = fileStateReference
const comparisonFile1: FileState = {
file: { ...TEST_FILE_DATA, fileMeta: { ...FILE_META, fileChecksum: "checksum3" } },
selectedAs: FileSelectionState.Comparison
}
const comparisonFile2: FileState = {
file: { ...TEST_FILE_DATA, fileMeta: { ...FILE_META, fileChecksum: "checksum4" } },
selectedAs: FileSelectionState.Comparison
}

const fileStates1 = [referenceFile1, comparisonFile1]
const fileStates2 = [referenceFile2, comparisonFile2]

expect(_onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(false)
})

it("should return false for different reference files", () => {
const referenceFile1: FileState = fileStateReference
const referenceFile2: FileState = {
file: { ...TEST_FILE_DATA, fileMeta: { ...FILE_META, fileChecksum: "checksum2" } },
selectedAs: FileSelectionState.Reference
}
const comparisonFile1: FileState = { ...fileStateNone, selectedAs: FileSelectionState.Comparison }
const comparisonFile2: FileState = { ...fileStateNone, selectedAs: FileSelectionState.Comparison }

const fileStates1 = [referenceFile1, comparisonFile1]
const fileStates2 = [referenceFile2, comparisonFile2]

expect(_onlyVisibleFilesMatterComparer(fileStates1, fileStates2)).toBe(false)
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@ import { FileSelectionState, FileState } from "../../../model/files/files"
import { createSelectorFactory, defaultMemoize } from "@ngrx/store"
import { filesSelector } from "../../store/files/files.selector"
import { getVisibleFileStates, isDeltaState } from "../../../model/files/files.helper"
import { compareContentIgnoringOrder } from "../../../util/arrayHelper"

function removeMatch(array: string[], target: string): string[] {
const matchIndex = array.indexOf(target)
return [...array.slice(0, matchIndex), ...array.slice(matchIndex + 1)]
}

export function onlyVisibleFilesMatterComparer(fileStates1: FileState[], fileStates2: FileState[]): boolean {
export function _onlyVisibleFilesMatterComparer(fileStates1: FileState[], fileStates2: FileState[]): boolean {
if (fileStates1 === fileStates2) {
return true
}
Expand All @@ -17,37 +13,47 @@ export function onlyVisibleFilesMatterComparer(fileStates1: FileState[], fileSta
return true
}

if (isDeltaState(fileStates1) !== isDeltaState(fileStates2)) {
return false
if (isDeltaState(fileStates1) || isDeltaState(fileStates2)) {
return compareDeltaState(fileStates1, fileStates2)
}

const visibleFileStates1 = fileStates1
.filter(file => file.selectedAs !== FileSelectionState.None)
.map(file => file.file.fileMeta.fileName)
let visibleFileStates2 = fileStates2
.filter(file => file.selectedAs !== FileSelectionState.None)
.map(file => file.file.fileMeta.fileName)
const visibleFileChecksums1 = fileStates1
.filter(file => file.selectedAs === FileSelectionState.Partial)
.map(file => file.file.fileMeta.fileChecksum)
const visibleFileChecksum2 = fileStates2
.filter(file => file.selectedAs === FileSelectionState.Partial)
.map(file => file.file.fileMeta.fileChecksum)

if (visibleFileStates1.length !== visibleFileStates2.length) {
if (visibleFileChecksums1.length !== visibleFileChecksum2.length) {
return false
}

function reduceToDetermineIfArraysContainSameContents(previousCallResult: boolean, arrayMember: any): boolean {
if (previousCallResult === false) {
return false
}
return compareContentIgnoringOrder(visibleFileChecksums1, visibleFileChecksum2)
}

if (visibleFileStates2.includes(arrayMember)) {
visibleFileStates2 = removeMatch(visibleFileStates2, arrayMember)
return true
}
function compareDeltaState(fileStates1: FileState[], fileStates2: FileState[]): boolean {
if (isDeltaState(fileStates1) !== isDeltaState(fileStates2)) {
return false
}

const referenceFile1 = fileStates1.find(file => file.selectedAs === FileSelectionState.Reference)
const referenceFile2 = fileStates2.find(file => file.selectedAs === FileSelectionState.Reference)
if (referenceFile1.file.fileMeta.fileChecksum !== referenceFile2.file.fileMeta.fileChecksum) {
return false
}

const comparisonFile1 = fileStates1.find(file => file.selectedAs === FileSelectionState.Comparison)
const comparisonFile2 = fileStates2.find(file => file.selectedAs === FileSelectionState.Comparison)
if (
comparisonFile1?.file.fileMeta.fileChecksum !== comparisonFile2?.file.fileMeta.fileChecksum ||
!comparisonFile1 !== !comparisonFile2
) {
return false
}

return visibleFileStates1.reduce(reduceToDetermineIfArraysContainSameContents, true)
return true
}

export const visibleFileStatesSelector = createSelectorFactory(projection =>
defaultMemoize(projection, onlyVisibleFilesMatterComparer, onlyVisibleFilesMatterComparer)
defaultMemoize(projection, _onlyVisibleFilesMatterComparer, _onlyVisibleFilesMatterComparer)
)(filesSelector, getVisibleFileStates)
85 changes: 84 additions & 1 deletion visualization/app/codeCharta/util/arrayHelper.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { addItemToArray, removeItemFromArray } from "./arrayHelper"
import { addItemToArray, compareContentIgnoringOrder, removeItemFromArray } from "./arrayHelper"

function mutateObject(object: Record<string, number>) {
object.x = 10_000
Expand Down Expand Up @@ -40,4 +40,87 @@ describe("arrayHelper", () => {
])
})
})

describe("compareContentIgnoringOrder", () => {
it("should return true for arrays with the same contents", () => {
const array1 = [
{ x: 1, y: 2 },
{ x: 3, y: 4 }
]
const array2 = [
{ x: 1, y: 2 },
{ x: 3, y: 4 }
]

const result = compareContentIgnoringOrder(array1, array2)

expect(result).toBe(true)
})

it("should return false for arrays with different contents", () => {
const array1 = [{ x: 1, y: 2 }]
const array2 = [{ x: 3, y: 4 }]

const result = compareContentIgnoringOrder(array1, array2)

expect(result).toBe(false)
})

it("should return true for arrays with the same contents in different orders", () => {
const array1 = [
{ x: 3, y: 4 },
{ x: 1, y: 2 }
]
const array2 = [
{ x: 1, y: 2 },
{ x: 3, y: 4 }
]

const result = compareContentIgnoringOrder(array1, array2)

expect(result).toBe(true)
})

it("should return false for arrays with different length", () => {
const array1 = [{ x: 3, y: 4 }]
const array2 = [
{ x: 3, y: 4 },
{ x: 3, y: 4 }
]

const result1 = compareContentIgnoringOrder(array1, array2)
const result2 = compareContentIgnoringOrder(array2, array1)

expect(result1).toBe(false)
expect(result2).toBe(false)
})

it("should return true for empty arrays", () => {
const array1 = []
const array2 = []

const result = compareContentIgnoringOrder(array1, array2)

expect(result).toBe(true)
})

it("should return false for arrays containing duplicate elements", () => {
const array1 = [
{ x: 1, y: 2 },
{ x: 1, y: 2 },
{ x: 1, y: 3 }
]
const array2 = [
{ x: 1, y: 2 },
{ x: 1, y: 3 },
{ x: 1, y: 3 }
]

const result1 = compareContentIgnoringOrder(array1, array2)
const result2 = compareContentIgnoringOrder(array2, array1)

expect(result1).toBe(false)
expect(result2).toBe(false)
})
})
})
Loading