threepipe
Version:
A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.
98 lines (85 loc) • 3.62 kB
text/typescript
import {describe, test, expect} from 'vitest'
import {incrementObjectCloneName} from './IObjectUi'
// minimal mock objects — only need name, parent, children
function mockObj(name: string, siblings: string[] = []): any {
const parent = {
children: siblings.map(n => ({name: n})),
}
const obj: any = {name, parent}
parent.children.push(obj)
return obj
}
describe('incrementObjectCloneName', () => {
test('adds (copy) suffix to a name without one', () => {
const obj = mockObj('Cube')
const clone: any = {name: ''}
incrementObjectCloneName(obj, clone)
expect(clone.name).toBe('Cube (copy)')
})
test('increments (copy) to (copy 2)', () => {
const obj = mockObj('Cube (copy)')
const clone: any = {name: ''}
incrementObjectCloneName(obj, clone)
expect(clone.name).toBe('Cube (copy 2)')
})
test('increments (copy 2) to (copy 3)', () => {
const obj = mockObj('Cube (copy 2)')
const clone: any = {name: ''}
incrementObjectCloneName(obj, clone)
expect(clone.name).toBe('Cube (copy 3)')
})
test('increments (copy 99) to (copy 100)', () => {
const obj = mockObj('Cube (copy 99)')
const clone: any = {name: ''}
incrementObjectCloneName(obj, clone)
expect(clone.name).toBe('Cube (copy 100)')
})
test('avoids name collisions with siblings', () => {
const obj = mockObj('Cube (copy)', ['Cube (copy 2)', 'Cube (copy 3)'])
const clone: any = {name: ''}
incrementObjectCloneName(obj, clone)
expect(clone.name).toBe('Cube (copy 4)')
})
test('uses custom name parameter', () => {
const obj = mockObj('Sphere')
const clone: any = {name: ''}
incrementObjectCloneName(obj, clone, 'CustomName')
expect(clone.name).toBe('CustomName (copy)')
})
test('uses custom name with existing copy suffix', () => {
const obj = mockObj('Sphere')
const clone: any = {name: ''}
incrementObjectCloneName(obj, clone, 'CustomName (copy 5)')
expect(clone.name).toBe('CustomName (copy 6)')
})
test('empty name string gets (copy) suffix', () => {
const obj = mockObj('')
const clone: any = {name: ''}
incrementObjectCloneName(obj, clone)
// Empty string has no "(copy)" match, so falls to else branch: '' + ' (copy)'
expect(clone.name).toBe(' (copy)')
})
test('name with nested copy patterns "Cube (copy 2) (copy 3)"', () => {
// The regex /\(copy( (\d+))?\)$/ matches the LAST "(copy N)" at end of string
const obj = mockObj('Cube (copy 2) (copy 3)')
const clone: any = {name: ''}
incrementObjectCloneName(obj, clone)
// match[2] = '3', so copyNum = 4
// replace replaces FIRST match of the regex, but $ anchors it to end
expect(clone.name).toBe('Cube (copy 2) (copy 4)')
})
test('object with no parent (null parent)', () => {
// Create an object with null parent
const obj: any = {name: 'Cube (copy)', parent: null}
const clone: any = {name: ''}
// The code checks `if (parent && parent !== clone.parent)` — null is falsy, so no sibling check
incrementObjectCloneName(obj, clone)
expect(clone.name).toBe('Cube (copy 2)')
})
test('object with undefined parent', () => {
const obj: any = {name: 'Cube', parent: undefined}
const clone: any = {name: ''}
incrementObjectCloneName(obj, clone)
expect(clone.name).toBe('Cube (copy)')
})
})