coh-content-db 1.4.1 → 2.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +25 -0
- package/.github/workflows/build.yml +38 -0
- package/.github/workflows/pull-request.yml +32 -0
- package/.github/workflows/release.yml +52 -0
- package/LICENSE +24 -674
- package/README.md +74 -17
- package/dist/coh-content-db.d.ts +584 -22
- package/dist/coh-content-db.js +587 -2
- package/dist/coh-content-db.js.map +1 -0
- package/dist/coh-content-db.mjs +568 -0
- package/dist/coh-content-db.mjs.map +1 -0
- package/eslint.config.mjs +30 -0
- package/jest.config.mjs +7 -0
- package/package.json +31 -23
- package/rollup.config.mjs +27 -0
- package/src/main/api/alignment.ts +3 -0
- package/src/main/api/alternate-data.ts +22 -0
- package/src/main/api/archetype-data.ts +5 -0
- package/src/main/api/badge-data.ts +109 -0
- package/src/main/api/badge-partial-data.ts +65 -0
- package/src/main/api/badge-partial-type.ts +8 -0
- package/src/main/api/badge-type.ts +19 -0
- package/src/main/api/change.ts +14 -0
- package/src/main/api/enhancement-category.ts +30 -0
- package/src/main/api/game-map-data.ts +26 -0
- package/src/main/api/link.ts +4 -0
- package/src/main/api/plaque-type.ts +6 -0
- package/src/main/api/server-group-data.ts +65 -0
- package/src/main/api/sex.ts +3 -0
- package/src/main/api/vidiot-map-data.ts +18 -0
- package/src/main/api/vidiot-map-point-of-interest-data.ts +30 -0
- package/src/main/changelog.ts +20 -0
- package/src/main/db/alternates.ts +81 -0
- package/src/main/db/archetype.ts +14 -0
- package/src/main/db/badge-partial.ts +35 -0
- package/src/main/db/badge.ts +141 -0
- package/src/main/db/coh-content-database.ts +29 -0
- package/src/main/db/game-map.ts +33 -0
- package/src/main/db/key.ts +18 -0
- package/src/main/db/server-group.ts +112 -0
- package/src/main/db/vidiot-map-point-of-interest.ts +40 -0
- package/src/main/db/vidiot-map.ts +25 -0
- package/src/main/index.ts +33 -0
- package/src/main/util.ts +17 -0
- package/src/test/api/alignment.test.ts +31 -0
- package/src/test/api/archetype-data.fixture.ts +8 -0
- package/src/test/api/badge-data.fixture.ts +22 -0
- package/src/test/api/badge-data.test.ts +15 -0
- package/src/test/api/badge-partial-data.fixture.ts +17 -0
- package/src/test/api/badge-partial-type.test.ts +31 -0
- package/src/test/api/badge-type.test.ts +35 -0
- package/src/test/api/enhancement-category.test.ts +35 -0
- package/src/test/api/game-map-data.fixture.ts +10 -0
- package/src/test/api/plaque-type.test.ts +31 -0
- package/src/test/api/server-group-data.fixture.ts +23 -0
- package/src/test/api/server-group-data.test.ts +15 -0
- package/src/test/api/sex.test.ts +31 -0
- package/src/test/api/vidiot-map-point-of-interest.fixture.ts +10 -0
- package/src/test/api/vidiot-map.fixture.ts +9 -0
- package/src/test/changelog.test.ts +36 -0
- package/src/test/db/alternates.test.ts +223 -0
- package/src/test/db/archetype.test.ts +38 -0
- package/src/test/db/badge.test.ts +41 -0
- package/src/test/db/coh-content-database.test.ts +42 -0
- package/src/test/db/key.test.ts +22 -0
- package/src/test/db/server-group.test.ts +124 -0
- package/src/test/index.test.ts +10 -0
- package/src/test/util.test.ts +39 -0
- package/tsconfig.json +117 -0
- package/dist/_changelog.d.ts +0 -3
- package/dist/coh-content-db.nomin.js +0 -635
- package/dist/content-refence-utils.d.ts +0 -4
- package/dist/index.d.ts +0 -8
- package/dist/internal/_common.d.ts +0 -4
- package/dist/internal/archetype.d.ts +0 -10
- package/dist/internal/badge.d.ts +0 -44
- package/dist/internal/game-map.d.ts +0 -33
- package/dist/internal/server-group.d.ts +0 -24
- package/dist/types/archetype.d.ts +0 -9
- package/dist/types/badge.d.ts +0 -192
- package/dist/types/enhancement.d.ts +0 -28
- package/dist/types/game-map.d.ts +0 -47
- package/dist/types/link.d.ts +0 -4
- package/dist/types/server-group.d.ts +0 -75
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BadgeData } from '../../main'
|
|
2
|
+
|
|
3
|
+
// If you change this test, update the example in the README as well
|
|
4
|
+
export const TEST_BADGE: BadgeData = {
|
|
5
|
+
key: 'test-badge',
|
|
6
|
+
type: 'ACHIEVEMENT',
|
|
7
|
+
name: [{ value: 'Test Badge' }, { alignment: 'P', value: 'My Badge for Praetorians' }],
|
|
8
|
+
alignment: ['H', 'V', 'P'],
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe('BadgeData', () => {
|
|
12
|
+
test('should be a usable interface', () => {
|
|
13
|
+
expect(TEST_BADGE).not.toBeNull()
|
|
14
|
+
})
|
|
15
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineFixture } from 'efate'
|
|
2
|
+
import { BADGE_PARTIAL_TYPE, BadgePartialData, ENHANCEMENT_CATEGORY, PLAQUE_TYPE } from '../../main'
|
|
3
|
+
|
|
4
|
+
export const badgePartialDataFixture = defineFixture<BadgePartialData>((t) => {
|
|
5
|
+
t.key.as(index => `badge-partial-${index}`)
|
|
6
|
+
t.type.pickFrom([...BADGE_PARTIAL_TYPE])
|
|
7
|
+
t.mapKey?.asString()
|
|
8
|
+
t.loc?.asArray()
|
|
9
|
+
t.plaqueType?.pickFrom([...PLAQUE_TYPE])
|
|
10
|
+
t.inscription?.asLoremIpsum()
|
|
11
|
+
t.vidiotMapKey?.asString()
|
|
12
|
+
t.badgeKey?.as(index => `badge-${index}`)
|
|
13
|
+
t.inventionLevel?.asNumber()
|
|
14
|
+
t.inventionTypes?.pickFrom([...ENHANCEMENT_CATEGORY])
|
|
15
|
+
t.inventionCount?.asNumber()
|
|
16
|
+
t.notes?.asLoremIpsum()
|
|
17
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { BADGE_PARTIAL_TYPE, BadgePartialType } from '../../main'
|
|
2
|
+
|
|
3
|
+
describe('BADGE_PARTIAL_TYPE', () => {
|
|
4
|
+
test('should be an array', () => {
|
|
5
|
+
expect(Array.isArray(BADGE_PARTIAL_TYPE)).toBeTruthy()
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
test('should not be empty', () => {
|
|
9
|
+
expect(BADGE_PARTIAL_TYPE).not.toHaveLength(0)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('should contain only strings', () => {
|
|
13
|
+
for (const entry of BADGE_PARTIAL_TYPE) {
|
|
14
|
+
expect(typeof entry).toBe('string')
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('should contain all known badge partial types', () => {
|
|
19
|
+
const expected = ['PLAQUE', 'BADGE', 'INVENTION', 'INVENTION_PLUS_ONE']
|
|
20
|
+
for (const category of expected) {
|
|
21
|
+
expect(BADGE_PARTIAL_TYPE).toContain(category)
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe('BadgePartialType', () => {
|
|
27
|
+
test('should be a usable type', () => {
|
|
28
|
+
const field: BadgePartialType = 'PLAQUE'
|
|
29
|
+
expect(field).toBe('PLAQUE')
|
|
30
|
+
})
|
|
31
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BADGE_TYPE, BadgeType } from '../../main'
|
|
2
|
+
|
|
3
|
+
describe('BADGE_TYPE', () => {
|
|
4
|
+
test('should be an array', () => {
|
|
5
|
+
expect(Array.isArray(BADGE_TYPE)).toBeTruthy()
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
test('should not be empty', () => {
|
|
9
|
+
expect(BADGE_TYPE).not.toHaveLength(0)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('should contain only strings', () => {
|
|
13
|
+
for (const entry of BADGE_TYPE) {
|
|
14
|
+
expect(typeof entry).toBe('string')
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('should contain all known basic badge types', () => {
|
|
19
|
+
const expected = [
|
|
20
|
+
'EXPLORATION', 'HISTORY', 'ACCOMPLISHMENT', 'ACHIEVEMENT', 'ACCOLADE',
|
|
21
|
+
'GLADIATOR', 'VETERAN', 'PVP', 'INVENTION', 'DEFEAT',
|
|
22
|
+
'EVENT', 'OUROBOROS', 'CONSIGNMENT', 'DAY_JOB', 'AE',
|
|
23
|
+
]
|
|
24
|
+
for (const category of expected) {
|
|
25
|
+
expect(BADGE_TYPE).toContain(category)
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
describe('BadgeType', () => {
|
|
31
|
+
test('should be a usable type', () => {
|
|
32
|
+
const field: BadgeType = 'EXPLORATION'
|
|
33
|
+
expect(field).toBe('EXPLORATION')
|
|
34
|
+
})
|
|
35
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ENHANCEMENT_CATEGORY, EnhancementCategory } from '../../main'
|
|
2
|
+
|
|
3
|
+
describe('ENHANCEMENT_CATEGORY', () => {
|
|
4
|
+
test('should be an array', () => {
|
|
5
|
+
expect(Array.isArray(ENHANCEMENT_CATEGORY)).toBeTruthy()
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
test('should not be empty', () => {
|
|
9
|
+
expect(ENHANCEMENT_CATEGORY).not.toHaveLength(0)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('should contain only strings', () => {
|
|
13
|
+
for (const entry of ENHANCEMENT_CATEGORY) {
|
|
14
|
+
expect(typeof entry).toBe('string')
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('should contain all known default enhancement categories', () => {
|
|
19
|
+
const expected = [
|
|
20
|
+
'DEFENSE_DEBUFF', 'TO_HIT_DEBUFF', 'TAUNT', 'CONFUSE', 'HEALING', 'DEFENSE_BUFF', 'RESIST_DAMAGE', 'INTANGIBILITY', 'SLEEP', 'SLOW', 'HOLD', 'STUN', 'IMMOBILIZE',
|
|
21
|
+
'FEAR', 'ENDURANCE_MODIFICATION', 'ENDURANCE_REDUCTION', 'RECHARGE_REDUCTION', 'INTERRUPT_DURATION', 'ACCURACY', 'TO_HIT_BUFF', 'DAMAGE', 'KNOCKBACK', 'RUN_SPEED',
|
|
22
|
+
'JUMP', 'FLY_SPEED', 'RANGE',
|
|
23
|
+
]
|
|
24
|
+
for (const category of expected) {
|
|
25
|
+
expect(ENHANCEMENT_CATEGORY).toContain(category)
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
describe('EnhancementCategory', () => {
|
|
31
|
+
test('should be a usable type', () => {
|
|
32
|
+
const field: EnhancementCategory = 'RUN_SPEED'
|
|
33
|
+
expect(field).toBe('RUN_SPEED')
|
|
34
|
+
})
|
|
35
|
+
})
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { GameMapData } from '../../main'
|
|
2
|
+
import { defineFixture } from 'efate'
|
|
3
|
+
import { vidiotMapFixture } from './vidiot-map.fixture'
|
|
4
|
+
|
|
5
|
+
export const gameMapDataFixture = defineFixture<GameMapData>((t) => {
|
|
6
|
+
t.key.as(index => `map-${index}`)
|
|
7
|
+
t.name.as(index => `Map ${index}`)
|
|
8
|
+
t.links?.asArray([{ href: 'https://nouri.org' }])
|
|
9
|
+
t.vidiotMaps?.arrayOfFixture({ fixture: vidiotMapFixture })
|
|
10
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { PLAQUE_TYPE, PlaqueType } from '../../main'
|
|
2
|
+
|
|
3
|
+
describe('PLAQUE_TYPE', () => {
|
|
4
|
+
test('should be an array', () => {
|
|
5
|
+
expect(Array.isArray(PLAQUE_TYPE)).toBeTruthy()
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
test('should not be empty', () => {
|
|
9
|
+
expect(PLAQUE_TYPE).not.toHaveLength(0)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('should contain only strings', () => {
|
|
13
|
+
for (const entry of PLAQUE_TYPE) {
|
|
14
|
+
expect(typeof entry).toBe('string')
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('should contain all known plaque types', () => {
|
|
19
|
+
const expected = ['WALL_PLAQUE', 'MONUMENT']
|
|
20
|
+
for (const category of expected) {
|
|
21
|
+
expect(PLAQUE_TYPE).toContain(category)
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe('PlaqueType', () => {
|
|
27
|
+
test('should be a usable type', () => {
|
|
28
|
+
const field: PlaqueType = 'WALL_PLAQUE'
|
|
29
|
+
expect(field).toBe('WALL_PLAQUE')
|
|
30
|
+
})
|
|
31
|
+
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineFixture } from 'efate'
|
|
2
|
+
import { Change, ServerGroupData } from '../../main'
|
|
3
|
+
import { archetypeDataFixture } from './archetype-data.fixture'
|
|
4
|
+
import { gameMapDataFixture } from './game-map-data.fixture'
|
|
5
|
+
import { badgeDataFixture } from './badge-data.fixture'
|
|
6
|
+
|
|
7
|
+
export const serverGroupDataFixture = defineFixture<ServerGroupData>((t) => {
|
|
8
|
+
t.key.as(index => `server-group-${index}`)
|
|
9
|
+
t.name.as(index => `Server Group ${index}`)
|
|
10
|
+
t.description?.asLoremIpsum()
|
|
11
|
+
t.repository?.as(index => `https://nouri.org?id=${index}`)
|
|
12
|
+
t.servers?.asArray()
|
|
13
|
+
t.archetypes?.arrayOfFixture({ fixture: archetypeDataFixture })
|
|
14
|
+
t.maps?.arrayOfFixture({ fixture: gameMapDataFixture })
|
|
15
|
+
t.badges?.arrayOfFixture({ fixture: badgeDataFixture })
|
|
16
|
+
t.changelog?.arrayOfFixture({
|
|
17
|
+
fixture: defineFixture<Change>((t) => {
|
|
18
|
+
t.version.as(index => `${index}`)
|
|
19
|
+
t.date.as(() => new Date())
|
|
20
|
+
t.description?.asLoremIpsum()
|
|
21
|
+
}),
|
|
22
|
+
})
|
|
23
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ServerGroupData } from '../../main'
|
|
2
|
+
import { TEST_BADGE } from './badge-data.test'
|
|
3
|
+
|
|
4
|
+
// If you change this test, update the example in the README as well
|
|
5
|
+
export const TEST_SERVER_GROUP: ServerGroupData = {
|
|
6
|
+
key: 'my-server-group',
|
|
7
|
+
name: 'My Server Group',
|
|
8
|
+
badges: [TEST_BADGE],
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe('ServerGroupData', () => {
|
|
12
|
+
test('should be a usable interface', () => {
|
|
13
|
+
expect(TEST_SERVER_GROUP).not.toBeNull()
|
|
14
|
+
})
|
|
15
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Sex, SEX } from '../../main'
|
|
2
|
+
|
|
3
|
+
describe('SEX', () => {
|
|
4
|
+
test('should be an array', () => {
|
|
5
|
+
expect(Array.isArray(SEX)).toBeTruthy()
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
test('should not be empty', () => {
|
|
9
|
+
expect(SEX).not.toHaveLength(0)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('should contain only strings', () => {
|
|
13
|
+
for (const entry of SEX) {
|
|
14
|
+
expect(typeof entry).toBe('string')
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('should contain all known sexes', () => {
|
|
19
|
+
const expected = ['M', 'F']
|
|
20
|
+
for (const category of expected) {
|
|
21
|
+
expect(SEX).toContain(category)
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe('Sex', () => {
|
|
27
|
+
test('should be a usable type', () => {
|
|
28
|
+
const field: Sex = 'M'
|
|
29
|
+
expect(field).toBe('M')
|
|
30
|
+
})
|
|
31
|
+
})
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { defineFixture } from 'efate'
|
|
2
|
+
import { VidiotMapPointOfInterest } from '../../main'
|
|
3
|
+
|
|
4
|
+
export const vidiotMapPointOfInterestFixture = defineFixture<VidiotMapPointOfInterest>((t) => {
|
|
5
|
+
t.pos?.as(index => [index, index])
|
|
6
|
+
t.notes?.asLoremIpsum()
|
|
7
|
+
t.mapKey?.as(index => `map-${index}`)
|
|
8
|
+
t.badgeKey?.as(index => `badge-${index}`)
|
|
9
|
+
t.badgePartialKey?.as(index => `partial-${index}`)
|
|
10
|
+
})
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { defineFixture } from 'efate'
|
|
2
|
+
import { VidiotMap } from '../../main'
|
|
3
|
+
import { vidiotMapPointOfInterestFixture } from './vidiot-map-point-of-interest.fixture'
|
|
4
|
+
|
|
5
|
+
export const vidiotMapFixture = defineFixture<VidiotMap>((t) => {
|
|
6
|
+
t.imageUrl.as(index => `https://nouri.org?id=${index}`)
|
|
7
|
+
t.name?.as(index => `Vidiot Map ${index}`)
|
|
8
|
+
t.pointsOfInterest?.arrayOfFixture({ fixture: vidiotMapPointOfInterestFixture })
|
|
9
|
+
})
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { CHANGELOG } from '../main'
|
|
2
|
+
|
|
3
|
+
describe('CHANGELOG', () => {
|
|
4
|
+
test('should be extant', () => {
|
|
5
|
+
expect(CHANGELOG).not.toBeNull()
|
|
6
|
+
expect(CHANGELOG).not.toBeUndefined()
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
test('should be an array', () => {
|
|
10
|
+
expect(Array.isArray(CHANGELOG)).toBeTruthy()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
test('should have only semver versions', () => {
|
|
14
|
+
// semver.org - https://regex101.com/r/vkijKf/1/
|
|
15
|
+
const pattern = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/
|
|
16
|
+
|
|
17
|
+
for (const change of CHANGELOG) {
|
|
18
|
+
expect(pattern.test(change.version)).toBeTruthy()
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('should have dates', () => {
|
|
23
|
+
for (const change of CHANGELOG) {
|
|
24
|
+
const date = change.date
|
|
25
|
+
expect(date).not.toBeNull()
|
|
26
|
+
expect(date).not.toBeUndefined()
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('should have descriptions', () => {
|
|
31
|
+
for (const change of CHANGELOG) {
|
|
32
|
+
expect(change).not.toBeNull()
|
|
33
|
+
expect(change).not.toBeUndefined()
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
})
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { Alternates } from '../../main/db/alternates'
|
|
2
|
+
|
|
3
|
+
describe(Alternates.name, () => {
|
|
4
|
+
describe('Constructor', () => {
|
|
5
|
+
test('should accept a list of alternate values', () => {
|
|
6
|
+
new Alternates([
|
|
7
|
+
{ value: 'Default' },
|
|
8
|
+
{ sex: 'M', value: 'Male' },
|
|
9
|
+
{ alignment: 'H', value: 'Hero' },
|
|
10
|
+
{ alignment: 'V', sex: 'M', value: 'Male Villain' },
|
|
11
|
+
{ alignment: 'P', sex: 'F', value: 'Praetorian Female' },
|
|
12
|
+
])
|
|
13
|
+
})
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
describe('getValue', () => {
|
|
17
|
+
test('should return undefined if there are no values', () => {
|
|
18
|
+
expect(new Alternates([]).getValue()).toBeUndefined()
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test('should return the least-specific value when no classifiers are provided', () => {
|
|
22
|
+
expect(new Alternates([
|
|
23
|
+
{ value: 'Default' },
|
|
24
|
+
{ sex: 'M', value: 'Male' },
|
|
25
|
+
{ alignment: 'H', value: 'Hero' },
|
|
26
|
+
{ alignment: 'V', sex: 'M', value: 'Male Villain' },
|
|
27
|
+
{ alignment: 'P', sex: 'F', value: 'Praetorian Female' },
|
|
28
|
+
]).getValue()).toBe('Default')
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('should return the least-specific value when no classifiers are provided, regardless of insert order', () => {
|
|
32
|
+
expect(new Alternates([
|
|
33
|
+
{ alignment: 'V', sex: 'M', value: 'Male Villain' },
|
|
34
|
+
{ alignment: 'H', value: 'Hero' },
|
|
35
|
+
{ value: 'Default' },
|
|
36
|
+
{ sex: 'M', value: 'Male' },
|
|
37
|
+
{ alignment: 'P', sex: 'F', value: 'Praetorian Female' },
|
|
38
|
+
]).getValue()).toBe('Default')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
test('should return the most specific match', () => {
|
|
42
|
+
expect(new Alternates([
|
|
43
|
+
{ value: 'Default' },
|
|
44
|
+
{ sex: 'M', value: 'Male' },
|
|
45
|
+
{ alignment: 'H', value: 'Hero' },
|
|
46
|
+
{ alignment: 'V', sex: 'M', value: 'Male Villain' },
|
|
47
|
+
{ alignment: 'P', sex: 'F', value: 'Praetorian Female' },
|
|
48
|
+
]).getValue('V', 'M')).toBe('Male Villain')
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('should return the most specific match, regardless of insert order', () => {
|
|
52
|
+
expect(new Alternates([
|
|
53
|
+
{ alignment: 'P', sex: 'F', value: 'Praetorian Female' },
|
|
54
|
+
{ sex: 'M', value: 'Male' },
|
|
55
|
+
{ alignment: 'H', value: 'Hero' },
|
|
56
|
+
{ alignment: 'V', sex: 'M', value: 'Male Villain' },
|
|
57
|
+
{ value: 'Default' },
|
|
58
|
+
]).getValue('V', 'M')).toBe('Male Villain')
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
test('should return undefined if there is no default', () => {
|
|
62
|
+
expect(new Alternates([
|
|
63
|
+
{ sex: 'M', value: 'Male' },
|
|
64
|
+
{ alignment: 'H', value: 'Hero' },
|
|
65
|
+
{ alignment: 'V', sex: 'M', value: 'Male Villain' },
|
|
66
|
+
{ alignment: 'P', sex: 'F', value: 'Praetorian Female' },
|
|
67
|
+
]).getValue()).toBeUndefined()
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
describe('default', () => {
|
|
72
|
+
test('should return undefined if there are no values', () => {
|
|
73
|
+
expect(new Alternates([]).default).toBeUndefined()
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
test('should return the lowest priority value', () => {
|
|
77
|
+
expect(new Alternates([
|
|
78
|
+
{ value: 'Default' },
|
|
79
|
+
{ sex: 'M', value: 'Male' },
|
|
80
|
+
{ alignment: 'H', value: 'Hero' },
|
|
81
|
+
{ alignment: 'V', sex: 'M', value: 'Male Villain' },
|
|
82
|
+
{ alignment: 'P', sex: 'F', value: 'Praetorian Female' },
|
|
83
|
+
]).default).toBe('Default')
|
|
84
|
+
|
|
85
|
+
expect(new Alternates([
|
|
86
|
+
{ alignment: 'V', sex: 'M', value: 'Male Villain' },
|
|
87
|
+
{ alignment: 'P', sex: 'F', value: 'Praetorian Female' },
|
|
88
|
+
{ sex: 'M', value: 'Male' },
|
|
89
|
+
{ value: 'Default' },
|
|
90
|
+
{ alignment: 'H', value: 'Hero' },
|
|
91
|
+
]).default).toBe('Default')
|
|
92
|
+
|
|
93
|
+
expect(new Alternates([
|
|
94
|
+
{ alignment: 'V', sex: 'M', value: 'Male Villain' },
|
|
95
|
+
{ alignment: 'P', sex: 'F', value: 'Praetorian Female' },
|
|
96
|
+
{ sex: 'M', value: 'Male' },
|
|
97
|
+
{ alignment: 'H', value: 'Hero' },
|
|
98
|
+
]).default).toBe('Male')
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
describe('canonical', () => {
|
|
103
|
+
test('should be empty if there are no values', () => {
|
|
104
|
+
expect(new Alternates([]).canonical).toHaveLength(0)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
test('should return values sorted in canonical order', () => {
|
|
108
|
+
const result = new Alternates([
|
|
109
|
+
{ alignment: 'H', sex: 'F', value: 'Female Hero' },
|
|
110
|
+
{ alignment: 'P', value: 'Praetorian' },
|
|
111
|
+
{ sex: 'F', value: 'Female' },
|
|
112
|
+
{ alignment: 'H', sex: 'A', value: 'A Hero' },
|
|
113
|
+
{ alignment: 'Y', sex: 'A', value: 'A Y' },
|
|
114
|
+
{ alignment: 'V', sex: 'M', value: 'Male Villain' },
|
|
115
|
+
{ alignment: 'V', sex: 'B', value: 'B Villain' },
|
|
116
|
+
{ alignment: 'P', sex: 'M', value: 'Male Praetorian' },
|
|
117
|
+
{ alignment: 'H', value: 'Hero' },
|
|
118
|
+
{ alignment: 'V', sex: 'A', value: 'A Villain' },
|
|
119
|
+
{ sex: 'A', value: 'A Sex' },
|
|
120
|
+
{ alignment: 'X', sex: 'F', value: 'Female X' },
|
|
121
|
+
{ alignment: 'H', sex: 'M', value: 'Male Hero' },
|
|
122
|
+
{ alignment: 'X', value: 'X' },
|
|
123
|
+
{ alignment: 'P', sex: 'B', value: 'B Praetorian' },
|
|
124
|
+
{ alignment: 'P', sex: 'A', value: 'A Praetorian' },
|
|
125
|
+
{ alignment: 'X', sex: 'M', value: 'Male X' },
|
|
126
|
+
{ sex: 'M', value: 'Male' },
|
|
127
|
+
{ alignment: 'X', sex: 'B', value: 'B X' },
|
|
128
|
+
{ alignment: 'H', sex: 'B', value: 'B Hero' },
|
|
129
|
+
{ alignment: 'V', value: 'Villain' },
|
|
130
|
+
{ alignment: 'Y', sex: 'M', value: 'Male Y' },
|
|
131
|
+
{ alignment: 'V', sex: 'F', value: 'Female Villain' },
|
|
132
|
+
{ sex: 'B', value: 'B Sex' },
|
|
133
|
+
{ alignment: 'Y', sex: 'B', value: 'B Y' },
|
|
134
|
+
{ alignment: 'P', sex: 'F', value: 'Female Praetorian' },
|
|
135
|
+
{ alignment: 'X', sex: 'A', value: 'A X' },
|
|
136
|
+
{ value: 'Default' },
|
|
137
|
+
{ alignment: 'Y', sex: 'F', value: 'Female Y' },
|
|
138
|
+
]).canonical
|
|
139
|
+
|
|
140
|
+
expect(result).toStrictEqual([
|
|
141
|
+
{ value: 'Default' },
|
|
142
|
+
{ sex: 'M', value: 'Male' },
|
|
143
|
+
{ sex: 'F', value: 'Female' },
|
|
144
|
+
{ sex: 'A', value: 'A Sex' },
|
|
145
|
+
{ sex: 'B', value: 'B Sex' },
|
|
146
|
+
{ alignment: 'H', value: 'Hero' },
|
|
147
|
+
{ alignment: 'V', value: 'Villain' },
|
|
148
|
+
{ alignment: 'P', value: 'Praetorian' },
|
|
149
|
+
{ alignment: 'X', value: 'X' },
|
|
150
|
+
{ alignment: 'H', sex: 'M', value: 'Male Hero' },
|
|
151
|
+
{ alignment: 'H', sex: 'F', value: 'Female Hero' },
|
|
152
|
+
{ alignment: 'H', sex: 'A', value: 'A Hero' },
|
|
153
|
+
{ alignment: 'H', sex: 'B', value: 'B Hero' },
|
|
154
|
+
{ alignment: 'V', sex: 'M', value: 'Male Villain' },
|
|
155
|
+
{ alignment: 'V', sex: 'F', value: 'Female Villain' },
|
|
156
|
+
{ alignment: 'V', sex: 'A', value: 'A Villain' },
|
|
157
|
+
{ alignment: 'V', sex: 'B', value: 'B Villain' },
|
|
158
|
+
{ alignment: 'P', sex: 'M', value: 'Male Praetorian' },
|
|
159
|
+
{ alignment: 'P', sex: 'F', value: 'Female Praetorian' },
|
|
160
|
+
{ alignment: 'P', sex: 'A', value: 'A Praetorian' },
|
|
161
|
+
{ alignment: 'P', sex: 'B', value: 'B Praetorian' },
|
|
162
|
+
{ alignment: 'X', sex: 'M', value: 'Male X' },
|
|
163
|
+
{ alignment: 'X', sex: 'F', value: 'Female X' },
|
|
164
|
+
{ alignment: 'X', sex: 'A', value: 'A X' },
|
|
165
|
+
{ alignment: 'X', sex: 'B', value: 'B X' },
|
|
166
|
+
{ alignment: 'Y', sex: 'M', value: 'Male Y' },
|
|
167
|
+
{ alignment: 'Y', sex: 'F', value: 'Female Y' },
|
|
168
|
+
{ alignment: 'Y', sex: 'A', value: 'A Y' },
|
|
169
|
+
{ alignment: 'Y', sex: 'B', value: 'B Y' },
|
|
170
|
+
])
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
test('should sort unspecified values by alpha', () => {
|
|
174
|
+
expect(new Alternates([
|
|
175
|
+
{ value: 'A' },
|
|
176
|
+
{ value: 'C' },
|
|
177
|
+
{ value: 'B' },
|
|
178
|
+
]).canonical).toStrictEqual([
|
|
179
|
+
{ value: 'A' },
|
|
180
|
+
{ value: 'B' },
|
|
181
|
+
{ value: 'C' },
|
|
182
|
+
])
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
test('should sort identical values similarly', () => {
|
|
186
|
+
expect(new Alternates([
|
|
187
|
+
{ value: 'A' },
|
|
188
|
+
{ value: 'B' },
|
|
189
|
+
{ value: 'C' },
|
|
190
|
+
{ value: 'B' },
|
|
191
|
+
]).canonical).toStrictEqual([
|
|
192
|
+
{ value: 'A' },
|
|
193
|
+
{ value: 'B' },
|
|
194
|
+
{ value: 'B' },
|
|
195
|
+
{ value: 'C' },
|
|
196
|
+
])
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
test('should sort unknown alignments by alpha', () => {
|
|
200
|
+
expect(new Alternates([
|
|
201
|
+
{ alignment: 'A', value: 'A' },
|
|
202
|
+
{ alignment: 'C', value: 'C' },
|
|
203
|
+
{ alignment: 'B', value: 'B' },
|
|
204
|
+
]).canonical).toStrictEqual([
|
|
205
|
+
{ alignment: 'A', value: 'A' },
|
|
206
|
+
{ alignment: 'B', value: 'B' },
|
|
207
|
+
{ alignment: 'C', value: 'C' },
|
|
208
|
+
])
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
test('should sort unknown sex by alpha', () => {
|
|
212
|
+
expect(new Alternates([
|
|
213
|
+
{ sex: 'A', value: 'A' },
|
|
214
|
+
{ sex: 'C', value: 'C' },
|
|
215
|
+
{ sex: 'B', value: 'B' },
|
|
216
|
+
]).canonical).toStrictEqual([
|
|
217
|
+
{ sex: 'A', value: 'A' },
|
|
218
|
+
{ sex: 'B', value: 'B' },
|
|
219
|
+
{ sex: 'C', value: 'C' },
|
|
220
|
+
])
|
|
221
|
+
})
|
|
222
|
+
})
|
|
223
|
+
})
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Archetype } from '../../main'
|
|
2
|
+
import { archetypeDataFixture } from '../api/archetype-data.fixture'
|
|
3
|
+
|
|
4
|
+
describe(Archetype.name, () => {
|
|
5
|
+
describe('Constructor', () => {
|
|
6
|
+
test('should accept the test fixture', () => {
|
|
7
|
+
new Archetype(archetypeDataFixture.create())
|
|
8
|
+
})
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
describe('key', () => {
|
|
12
|
+
test('should be set from data', () => {
|
|
13
|
+
const data = archetypeDataFixture.create({ key: 'foo' })
|
|
14
|
+
expect(new Archetype(data).key).toBe('foo')
|
|
15
|
+
})
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
describe('name', () => {
|
|
19
|
+
test('should be set from data', () => {
|
|
20
|
+
const data = archetypeDataFixture.create({ name: 'foo' })
|
|
21
|
+
expect(new Archetype(data).name).toBe('foo')
|
|
22
|
+
})
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
describe('description', () => {
|
|
26
|
+
test('should be set from data', () => {
|
|
27
|
+
const data = archetypeDataFixture.create({ description: 'foo' })
|
|
28
|
+
expect(new Archetype(data).description).toBe('foo')
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('should be undefined if missing in data', () => {
|
|
32
|
+
const data = archetypeDataFixture
|
|
33
|
+
.omit('description')
|
|
34
|
+
.create()
|
|
35
|
+
expect(new Archetype(data).description).toBeUndefined()
|
|
36
|
+
})
|
|
37
|
+
})
|
|
38
|
+
})
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Badge } from '../../main'
|
|
2
|
+
import { badgeDataFixture } from '../api/badge-data.fixture'
|
|
3
|
+
import { badgePartialDataFixture } from '../api/badge-partial-data.fixture'
|
|
4
|
+
|
|
5
|
+
describe(Badge.name, () => {
|
|
6
|
+
describe('Constructor', () => {
|
|
7
|
+
test(`should accept the test fixture`, () => {
|
|
8
|
+
new Badge(badgeDataFixture.create())
|
|
9
|
+
})
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
describe('partials', () => {
|
|
13
|
+
test(`should throw an error on duplicate key`, () => {
|
|
14
|
+
const data = badgeDataFixture.create({
|
|
15
|
+
partials: [
|
|
16
|
+
badgePartialDataFixture.create({ key: 'foo' }),
|
|
17
|
+
badgePartialDataFixture.create({ key: 'foo' }),
|
|
18
|
+
],
|
|
19
|
+
})
|
|
20
|
+
expect(() => new Badge(data)).toThrow('Duplicate badge partial key [foo]')
|
|
21
|
+
})
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
describe('getBadgePartial', () => {
|
|
25
|
+
test(`should retrieve partial from the index`, () => {
|
|
26
|
+
const data = badgeDataFixture.create({
|
|
27
|
+
partials: [badgePartialDataFixture.create({ key: 'foo' })],
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
expect(new Badge(data).getPartial('foo')).not.toBeNull()
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test(`should throw error for unknown partial`, () => {
|
|
34
|
+
const data = badgeDataFixture.create({
|
|
35
|
+
partials: [],
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
expect(() => new Badge(data).getPartial('foo')).toThrow('Unknown badge partial key [foo]')
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
})
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { CohContentDatabase } from '../../main'
|
|
2
|
+
import { serverGroupDataFixture } from '../api/server-group-data.fixture'
|
|
3
|
+
|
|
4
|
+
describe(CohContentDatabase.name, () => {
|
|
5
|
+
test('should be instantiable', () => {
|
|
6
|
+
expect(new CohContentDatabase()).not.toBeNull()
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
describe(CohContentDatabase.prototype.loadServerGroupData.name, () => {
|
|
10
|
+
test('should load an empty server group', () => {
|
|
11
|
+
const database = new CohContentDatabase()
|
|
12
|
+
database.loadServerGroupData(serverGroupDataFixture.create())
|
|
13
|
+
})
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
describe(CohContentDatabase.prototype.listServerGroups.name, () => {
|
|
17
|
+
test('should load two server groups', () => {
|
|
18
|
+
const database = new CohContentDatabase()
|
|
19
|
+
database.loadServerGroupData(serverGroupDataFixture.create({ key: 'sg1' }))
|
|
20
|
+
database.loadServerGroupData(serverGroupDataFixture.create({ key: 'sg2' }))
|
|
21
|
+
|
|
22
|
+
const sgs = database.listServerGroups()
|
|
23
|
+
|
|
24
|
+
expect(sgs).toHaveLength(2)
|
|
25
|
+
|
|
26
|
+
for (const entry of sgs) {
|
|
27
|
+
expect(['sg1', 'sg2']).toContain(entry.key)
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
describe(CohContentDatabase.prototype.getServerGroup.name, () => {
|
|
33
|
+
test('should load a server group by key', () => {
|
|
34
|
+
const database = new CohContentDatabase()
|
|
35
|
+
database.loadServerGroupData(serverGroupDataFixture.create({ key: 'sg1' }))
|
|
36
|
+
|
|
37
|
+
const sg = database.getServerGroup('sg1')
|
|
38
|
+
expect(sg).not.toBeNull()
|
|
39
|
+
expect(sg?.key).toEqual('sg1')
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
})
|