import { test } from '@japa/runner'
import { JSDOM } from 'jsdom'
import { DataDomain, DomainEntity, DomainModel, DomainProperty } from '../../../src/index.js'

const rfc3339Re = /^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}Z$/
const dateRe = /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/
const timeRe = /^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/
const mime = 'application/xml'

test.group('XML DomainEntity Generator: string', (group) => {
  let e1: DomainEntity

  group.each.setup(() => {
    const ns = new DataDomain()
    const d1 = ns.addModel({ key: 'd1', info: { name: 'd1' } })
    e1 = d1.addEntity({ key: 'e1', info: { name: 'e1' } })
  })

  test('generates an example', ({ assert }) => {
    e1.addProperty({ key: 'p1', info: { name: 'p1' } })
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    assert.isNotEmpty(inner.textContent!.trim(), 'has the generated content')
  })

  test('has min length with schema', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', info: { name: 'p1' } })
    p1.schema = {
      minimum: 10,
    }

    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const inner = schema.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()
    assert.isAtLeast(value.length, 10, 'has the minimum length')
  })

  test('has max length with schema', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', info: { name: 'p1' } })
    p1.schema = {
      maximum: 10,
    }

    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document
    const inner = schema.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()
    assert.isAtMost(value.length, 10, 'has the maximum length')
  })

  test('returns an array when multiple property', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', info: { name: 'p1' } })
    p1.multiple = true
    const result = e1.toExample(mime) as string

    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document
    assert.lengthOf(schema.querySelectorAll('e1'), 1, 'has the parent')
    assert.lengthOf(schema.querySelectorAll('e1 p1'), 1, 'has only one property')
    const inner = schema.querySelector('p1')!
    const value = inner.textContent!.trim()
    assert.isAtMost(value.length, 10, 'has the maximum length')
  })

  test('returns example value when defined on the mime type scheme', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', info: { name: 'p1' } })
    p1.schema = {
      minimum: 1,
      maximum: 3,
      examples: ['test123'],
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')
    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document
    assert.lengthOf(schema.querySelectorAll('e1'), 1, 'has the parent')
    assert.lengthOf(schema.querySelectorAll('e1 p1'), 1, 'has only one property')
    const inner = schema.querySelector('p1')!
    const value = inner.textContent!.trim()
    assert.equal(value, 'test123', 'has the example value')
  })

  test('returns all example values with multiple property', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', info: { name: 'p1' } })
    p1.multiple = true
    p1.schema = {
      examples: ['test123', '123test'],
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')
    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document
    const ps = schema.querySelectorAll('p1')
    assert.lengthOf(ps, 2, 'has an example')
    assert.equal(ps[0].textContent!.trim(), 'test123')
    assert.equal(ps[1].textContent!.trim(), '123test')
  })

  test('returns the default value when defined', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', info: { name: 'p1' } })
    p1.schema = {
      defaultValue: { value: 'test123', type: 'literal' },
    }

    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    assert.lengthOf(schema.querySelectorAll('e1'), 1, 'has the parent')
    assert.lengthOf(schema.querySelectorAll('e1 p1'), 1, 'has only one property')
    const inner = schema.querySelector('p1')!
    const value = inner.textContent!.trim()
    assert.equal(value, 'test123', 'has the default value')
  })

  test('returns the default value when multiple property', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', info: { name: 'p1' } })
    p1.multiple = true
    p1.schema = {
      defaultValue: { value: 'test123', type: 'literal' },
    }
    const result = e1.toExample(mime) as string

    assert.typeOf(result, 'string', 'result is a string')
    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    assert.lengthOf(schema.querySelectorAll('e1'), 1, 'has the parent')
    assert.lengthOf(schema.querySelectorAll('e1 p1'), 1, 'has only one property')
    const inner = schema.querySelector('p1')!
    const value = inner.textContent!.trim()
    assert.equal(value, 'test123', 'has the default value')
  })

  test('respects both the min and max length', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', info: { name: 'p1' } })
    p1.schema = {
      minimum: 15,
      maximum: 30,
    }

    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    assert.lengthOf(schema.querySelectorAll('e1'), 1, 'has the parent')
    assert.lengthOf(schema.querySelectorAll('e1 p1'), 1, 'has only one property')
    const inner = schema.querySelector('p1')!
    const value = inner.textContent!.trim()

    assert.isAtLeast(value.length, 15, 'has the minimum length')
    assert.isAtMost(value.length, 30, 'has the maximum length')
  })
})

test.group('XML DomainEntity Generator: number', (group) => {
  let e1: DomainEntity

  group.each.setup(() => {
    const ns = new DataDomain()
    const d1 = ns.addModel({ key: 'd1', info: { name: 'd1' } })
    e1 = d1.addEntity({ key: 'e1', info: { name: 'e1' } })
  })

  test('generates an example value', ({ assert }) => {
    e1.addProperty({ key: 'p1', type: 'number', info: { name: 'p1' } })
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    assert.match(inner.textContent!.trim(), /^\d+$/, 'has the property number')
  })

  test('has the minimum value', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'number', info: { name: 'p1' } })
    p1.schema = {
      minimum: 10,
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())
    assert.isAtLeast(value, 10, 'has the minimum length')
  })

  test('has the maximum value', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'number', info: { name: 'p1' } })
    p1.schema = {
      maximum: 10,
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())
    assert.isAtMost(value, 10, 'has the maximum length')
  })

  test('respects both the min and max', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'number', info: { name: 'p1' } })
    p1.schema = {
      minimum: 5,
      maximum: 10,
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())

    assert.isAtLeast(value, 5, 'has the minimum length')
    assert.isAtMost(value, 10, 'has the maximum length')
  })

  // Note, this may randomly fail because the data generation library does not
  // guarantee to always generate a float (it does generate a float but with `.00` value).
  test('generates a floating-point number for a float format', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'number', info: { name: 'p1' } })
    p1.bindings = [
      {
        type: 'web',
        schema: {
          format: 'float',
        },
      },
    ]
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())
    assert.isNotNaN(value)
    // const rest = value % 1;
    // assert.isAbove(rest, 0, 'module is above 0');
    // assert.isBelow(rest, 1, 'module is below 0');
  })

  test('generates a floating-point number for a double format', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'number', info: { name: 'p1' } })
    p1.bindings = [
      {
        type: 'web',
        schema: {
          format: 'double',
        },
      },
    ]
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())
    assert.isNotNaN(value)
    // const rest = value % 1;
    // assert.isAbove(rest, 0, 'module is above 0');
    // assert.isBelow(rest, 1, 'module is below 0');
  })

  test('returns an array number property when multiple property', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'number', info: { name: 'p1' } })
    p1.multiple = true
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())
    assert.isNotNaN(value)
  })

  test('respects the "multipleOf" schema property', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'number', info: { name: 'p1' } })
    p1.schema = {
      multipleOf: 5,
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())
    assert.equal(value % 5, 0, 'has a value multipliable by 5')
  })

  test('returns the example value', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'number', info: { name: 'p1' } })
    p1.schema = {
      examples: ['1', '2', '3'],
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())

    assert.equal(value, 1, 'has the first example')
  })

  test('returns all examples when multiple property', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'number', info: { name: 'p1' } })
    p1.multiple = true
    p1.schema = {
      examples: ['1', '2', '3'],
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')

    const params = outer.querySelectorAll('p1')
    assert.lengthOf(params, 3, 'has all example values')
    assert.equal(params[0].textContent!.trim(), '1')
    assert.equal(params[1].textContent!.trim(), '2')
    assert.equal(params[2].textContent!.trim(), '3')
  })

  test('returns the default value', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'number', info: { name: 'p1' } })
    p1.schema = {
      defaultValue: { value: '123', type: 'literal' },
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())

    assert.equal(value, 123, 'has the first example')
  })
})

test.group('XML DomainEntity Generator: int64 format', (group) => {
  let e1: DomainEntity
  let p1: DomainProperty

  group.each.setup(() => {
    const ns = new DataDomain()
    const d1 = ns.addModel({ key: 'd1', info: { name: 'd1' } })
    e1 = d1.addEntity({ key: 'e1', info: { name: 'e1' } })
    p1 = e1.addProperty({ key: 'p1', type: 'number', info: { name: 'p1' } })
    p1.getWebBinding().format = 'int64'
  })

  test('generates an example value', ({ assert }) => {
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())

    assert.typeOf(value, 'number', 'has the property number')
  })

  test('has the minimum value', ({ assert }) => {
    p1.schema = {
      minimum: 10,
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())

    assert.isAtLeast(value, 10, 'has the minimum length')
  })

  test('has the maximum value', ({ assert }) => {
    p1.schema = {
      maximum: 10,
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())

    assert.isAtMost(value, 10, 'has the maximum length')
  })

  test('respects both the min and max', ({ assert }) => {
    p1.schema = {
      minimum: 5,
      maximum: 10,
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())

    assert.isAtLeast(value, 5, 'has the minimum length')
    assert.isAtMost(value, 10, 'has the maximum length')
  })

  test('generates an integer for an int32 format', ({ assert }) => {
    p1.bindings = [
      {
        type: 'web',
        schema: {
          format: 'int32',
        },
      },
    ]
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())

    const rest = value % 1
    assert.equal(rest, 0, 'module is 0')
  })

  test('generates an integer for an int64 format', ({ assert }) => {
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())

    const rest = value % 1
    assert.equal(rest, 0, 'module is 0')
  })

  test('returns an array number property when multiple property', ({ assert }) => {
    p1.multiple = true
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())

    assert.typeOf(value, 'number', 'has a final value correct type')
  })

  test('respects the "multipleOf" schema property', ({ assert }) => {
    p1.schema = {
      multipleOf: 5,
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())

    assert.equal(value % 5, 0, 'has a value multipliable by 5')
  })

  test('returns the example value', ({ assert }) => {
    p1.schema = {
      examples: ['1', '2', '3'],
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())

    assert.equal(value, 1, 'has the first example')
  })

  test('returns all examples when multiple property', ({ assert }) => {
    p1.multiple = true
    p1.schema = {
      examples: ['1', '2', '3'],
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')

    const params = outer.querySelectorAll('p1')
    assert.lengthOf(params, 3, 'has all example values')
    assert.equal(params[0].textContent!.trim(), '1')
    assert.equal(params[1].textContent!.trim(), '2')
    assert.equal(params[2].textContent!.trim(), '3')
  })

  test('returns the default value', ({ assert }) => {
    p1.schema = {
      defaultValue: { value: '123', type: 'literal' },
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = Number(inner.textContent!.trim())

    assert.deepEqual(value, 123, 'has the first example')
  })
})

test.group('XML DomainEntity Generator: date', (group) => {
  let e1: DomainEntity

  group.each.setup(() => {
    const ns = new DataDomain()
    const d1 = ns.addModel({ key: 'd1', info: { name: 'd1' } })
    e1 = d1.addEntity({ key: 'e1', info: { name: 'e1' } })
  })

  test('generates an example', ({ assert }) => {
    e1.addProperty({ key: 'p1', type: 'date', info: { name: 'p1' } })
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()

    assert.match(value, dateRe)
  })

  test('generates an example with the multiple property', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'date', info: { name: 'p1' } })
    p1.multiple = true
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()

    assert.match(value, dateRe)
  })

  test('returns the default value', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'date', info: { name: 'p1' } })
    p1.schema = {
      defaultValue: { value: '2022-08-08', type: 'literal' },
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()

    assert.equal(value, '2022-08-08')
  })

  test('returns the default value as array with multiple property', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'date', info: { name: 'p1' } })
    p1.multiple = true
    p1.schema = {
      defaultValue: { value: '2022-08-08', type: 'literal' },
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()

    assert.equal(value, '2022-08-08')
  })

  test('returns the example value', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'date', info: { name: 'p1' } })
    p1.schema = {
      examples: ['2022-08-08', '2022-08-09'],
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()

    assert.equal(value, '2022-08-08')
  })

  test('returns the default value as array with multiple property', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'date', info: { name: 'p1' } })
    p1.multiple = true
    p1.schema = {
      examples: ['2022-08-08', '2022-08-09'],
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const properties = outer.querySelectorAll('p1')
    assert.lengthOf(properties, 2, 'has both examples')

    assert.equal(properties[0].textContent!.trim(), '2022-08-08')
    assert.equal(properties[1].textContent!.trim(), '2022-08-09')
  })
})

test.group('XML DomainEntity Generator: datetime', (group) => {
  let e1: DomainEntity

  group.each.setup(() => {
    const ns = new DataDomain()
    const d1 = ns.addModel({ key: 'd1', info: { name: 'd1' } })
    e1 = d1.addEntity({ key: 'e1', info: { name: 'e1' } })
  })

  test('generates an example with default format', ({ assert }) => {
    e1.addProperty({ key: 'p1', type: 'datetime', info: { name: 'p1' } })
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()

    assert.match(value, rfc3339Re)
  })

  test('returns the default value', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'datetime', info: { name: 'p1' } })
    p1.schema = {
      defaultValue: { value: '2036-01-04T19:49:30.224Z', type: 'literal' },
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()

    assert.equal(value, '2036-01-04T19:49:30.224Z')
  })

  test('returns the default value as array with multiple property', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'datetime', info: { name: 'p1' } })
    p1.multiple = true
    p1.schema = {
      defaultValue: { value: '2036-01-04T19:49:30.224Z', type: 'literal' },
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()

    assert.equal(value, '2036-01-04T19:49:30.224Z')
  })

  test('returns the example value', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'datetime', info: { name: 'p1' } })
    p1.schema = {
      examples: ['2036-01-04T19:49:30.224Z', '2036-01-05T19:49:30.224Z'],
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()

    assert.equal(value, '2036-01-04T19:49:30.224Z')
  })

  test('returns the default value as array with multiple property', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'datetime', info: { name: 'p1' } })
    p1.multiple = true
    p1.schema = {
      examples: ['2036-01-04T19:49:30.224Z', '2036-01-05T19:49:30.224Z'],
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const params = outer.querySelectorAll('p1')
    assert.lengthOf(params, 2, 'has both example values')

    assert.deepEqual(params[0].textContent!.trim(), '2036-01-04T19:49:30.224Z')
    assert.deepEqual(params[1].textContent!.trim(), '2036-01-05T19:49:30.224Z')
  })
})

test.group('XML DomainEntity Generator: time', (group) => {
  let e1: DomainEntity

  group.each.setup(() => {
    const ns = new DataDomain()
    const d1 = ns.addModel({ key: 'd1', info: { name: 'd1' } })
    e1 = d1.addEntity({ key: 'e1', info: { name: 'e1' } })
  })

  test('generates an example', ({ assert }) => {
    e1.addProperty({ key: 'p1', type: 'time', info: { name: 'p1' } })
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()

    assert.match(value, timeRe)
  })

  test('generates an example with multiple property', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'time', info: { name: 'p1' } })
    p1.multiple = true
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()

    assert.match(value, timeRe)
  })

  test('returns the default value', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'time', info: { name: 'p1' } })
    p1.schema = {
      defaultValue: { value: '2080-02-04T09:39:13', type: 'literal' },
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()

    assert.equal(value, '2080-02-04T09:39:13')
  })

  test('returns the default value as array with multiple property', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'time', info: { name: 'p1' } })
    p1.multiple = true
    p1.schema = {
      defaultValue: { value: '2080-02-04T09:39:13', type: 'literal' },
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()

    assert.deepEqual(value, '2080-02-04T09:39:13')
  })

  test('returns the example value', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'time', info: { name: 'p1' } })
    p1.schema = {
      examples: ['2080-02-04T09:39:13', '2080-02-05T09:39:13'],
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()

    assert.equal(value, '2080-02-04T09:39:13')
  })

  test('returns the default value as array with multiple property', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'time', info: { name: 'p1' } })
    p1.multiple = true
    p1.schema = {
      examples: ['2080-02-04T09:39:13', '2080-02-05T09:39:13'],
    }
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const params = outer.querySelectorAll('p1')
    assert.lengthOf(params, 2, 'has both example values')

    assert.equal(params[0].textContent!.trim(), '2080-02-04T09:39:13')
    assert.equal(params[1].textContent!.trim(), '2080-02-05T09:39:13')
  })
})

test.group('XML DomainEntity Generator: boolean', (group) => {
  let e1: DomainEntity

  group.each.setup(() => {
    const ns = new DataDomain()
    const d1 = ns.addModel({ key: 'd1', info: { name: 'd1' } })
    e1 = d1.addEntity({ key: 'e1', info: { name: 'e1' } })
  })

  test('generates an example', ({ assert }) => {
    e1.addProperty({ key: 'p1', type: 'boolean', info: { name: 'p1' } })
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()

    assert.match(value, /^true|false$/, 'has the boolean value')
  })

  test('generates an example with multiple property', ({ assert }) => {
    const p1 = e1.addProperty({ key: 'p1', type: 'boolean', info: { name: 'p1' } })
    p1.multiple = true
    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')
    const inner = outer.querySelector('p1')!
    assert.ok(inner, 'has the inner element')
    const value = inner.textContent!.trim()

    assert.match(value, /^true|false$/, 'has the boolean value')
  })
})

// test.group('XML DomainEntity Generator: nil', (group) => {
//   let e1: DomainEntity

//   group.each.setup(() => {
//     const ns = new DataDomain()
//     const d1 = ns.addModel({ key: 'd1', info: { name: 'd1' } })
//     e1 = d1.addEntity({ key: 'e1', info: { name: 'e1' } })
//   })

//   test('generates an example', ({ assert }) => {
//     e1.addTypedProperty('nil', 'p1')
//     const result = e1.toExample(mime) as string
//     assert.typeOf(result, 'string', 'result is a string')

//     const dom = new JSDOM(result, { contentType: mime })
//     const schema = dom.window.document

//     const outer = schema.querySelector('e1')!
//     assert.ok(outer, 'has the outer element')
//     const inner = outer.querySelector('p1')!
//     assert.ok(inner, 'has the inner element')
//     const value = inner.textContent!.trim()

//     assert.isEmpty(value)
//   })

//   test('generates an example with multiple property', ({ assert }) => {
//     const p1 = e1.addTypedProperty('nil', 'p1')
//     p1.multiple = true
//     const result = e1.toExample(mime) as string
//     assert.typeOf(result, 'string', 'result is a string')

//     const dom = new JSDOM(result, { contentType: mime })
//     const schema = dom.window.document

//     const outer = schema.querySelector('e1')!
//     assert.ok(outer, 'has the outer element')
//     const inner = outer.querySelector('p1')!
//     assert.ok(inner, 'has the inner element')
//     const value = inner.textContent!.trim()

//     assert.isEmpty(value)
//   })
// })

test.group('XML DomainEntity Generator: associations', (group) => {
  let d1: DomainModel
  let e1: DomainEntity
  let e2: DomainEntity

  group.each.setup(() => {
    const ns = new DataDomain()
    d1 = ns.addModel({ key: 'd1', info: { name: 'd1' } })
    e1 = d1.addEntity({ key: 'e1', info: { name: 'e1' } })
    e2 = d1.addEntity({ key: 'e2', info: { name: 'e2' } })
  })

  test('creates a property from an association', ({ assert }) => {
    e2.addProperty({ type: 'number', key: 'n1', info: { name: 'n1' } })
    e1.addAssociation({ key: e2.key }, { key: 'a1', info: { name: 'a1' } })

    const result = e1.toExample(mime) as string

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')

    const a1Element = outer.querySelector('a1')!
    assert.ok(a1Element, 'has the association as Element')

    const n1Element = a1Element.querySelector('n1')!
    assert.ok(n1Element, 'has the target property as element')

    assert.match(n1Element.textContent!.trim(), /^\d+$/, 'has the association properties')
  })

  test('creates a deep association', ({ assert }) => {
    const e3 = d1.addEntity({ key: 'e3', info: { name: 'e3' } })
    e3.addProperty({ type: 'number', key: 'i1', info: { name: 'i1' } })
    e2.addProperty({ type: 'number', key: 'n1', info: { name: 'n1' } })
    e1.addAssociation({ key: e2.key }, { key: 'a1', info: { name: 'a1' } })
    e2.addAssociation({ key: e3.key }, { key: 'a2', info: { name: 'a2' } })

    const result = e1.toExample(mime) as string

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e1')!
    assert.ok(outer, 'has the outer element')

    const a1Element = outer.querySelector('a1')!
    assert.ok(a1Element, 'has the association as Element')

    const n1Element = a1Element.querySelector('n1')!
    assert.ok(n1Element, 'has the target property as element')

    assert.match(n1Element.textContent!.trim(), /^\d+$/, 'has the association properties')

    const a2Element = a1Element.querySelector('a2')!
    assert.ok(a2Element, 'has the deep association as Element')

    const i1Element = a2Element.querySelector('i1')!
    assert.ok(i1Element, 'has the deep target property as element')

    assert.match(i1Element.textContent!.trim(), /^\d+$/, 'has the association properties')
  })

  test('does not make associations to self (recursive #1)', ({ assert }) => {
    e1.addAssociation({ key: e1.key }, { key: 'a1' })
    const result = e1.toExample(mime) as string

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const elements = schema.querySelectorAll('e1')
    assert.lengthOf(elements, 1)
  })

  test('does not make recursive associations (recursive #2)', ({ assert }) => {
    const e3 = d1.addEntity({ key: 'e3', info: { name: 'e3' } })
    e3.addProperty({ type: 'number', key: 'i1', info: { name: 'i1' } })
    e2.addProperty({ type: 'number', key: 'n1', info: { name: 'n1' } })
    e1.addAssociation({ key: e2.key }, { key: 'a1', info: { name: 'a1' } })
    e2.addAssociation({ key: e3.key }, { key: 'a2', info: { name: 'a2' } })
    e3.addAssociation({ key: e1.key }, { key: 'a3', info: { name: 'a3' } })

    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const a3Element = schema.querySelectorAll('a3')
    assert.lengthOf(a3Element, 0)
  })

  test('returns the default union result', ({ assert }) => {
    const e3 = d1.addEntity({ key: 'e3', info: { name: 'e3' } })
    e3.addProperty({ type: 'number', key: 'i1', info: { name: 'i1' } })
    e2.addProperty({ type: 'string', key: 's1', info: { name: 's1' } })
    const a1 = e1.addAssociation({ key: e2.key }, { key: 'a1', info: { name: 'a1' } })
    a1.addTarget(e3.key)

    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const s1Element = schema.querySelector('e1 a1 s1')
    assert.ok(s1Element)
  })

  // test('returns the default union result with multiple', ({ assert }) => {
  //   const e3 = d1.addEntity({ key: 'e3', info: { name: 'e3' } });
  //   e3.addTypedProperty('integer', 'i1');
  //   e2.addProperty({ type: 'string', key: 's1', info: { name: 's1' } });
  //   const a1 = e1.addAssociation({ key: e2.key }, { key: 'a1', info: { name: 'a1' } });
  //   a1.addTarget(e3.key);
  //   a1.multiple = true;

  //   const result = e1.toExample(mime) as string;
  //   assert.typeOf(result, 'string', 'result is a string');

  //   const dom = new JSDOM(result, { contentType: mime });
  //   const schema = dom.window.document;
  //   console.log(result);

  //   const data = JSON.parse(result);
  //   assert.typeOf(data.a1, 'array', 'has the association property as an array');
  //   const [prop] = data.a1;
  //   assert.typeOf(prop, 'object', 'has the item in the array');
  //   assert.typeOf(prop.s1, 'string', 'has the association properties');
  // });

  test('returns the schema for anyOf union', ({ assert }) => {
    const e3 = d1.addEntity({ key: 'e3', info: { name: 'e3' } })

    e2.addProperty({ type: 'string', key: 's1', info: { name: 's1' } })
    e3.addProperty({ type: 'number', key: 'i1', info: { name: 'i1' } })

    const a1 = e1.addAssociation({ key: e2.key }, { key: 'a1', info: { name: 'a1' } })
    a1.addTarget(e3.key)

    a1.schema = { unionType: 'anyOf' }

    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const s1Element = schema.querySelector('e1 a1 s1')
    assert.ok(s1Element)

    const i1Element = schema.querySelector('e1 a1 i1')
    assert.notOk(i1Element)
  })

  test('returns the schema for allOf union', ({ assert }) => {
    const e3 = d1.addEntity({ key: 'e3', info: { name: 'e3' } })
    e3.addProperty({ type: 'number', key: 'i1', info: { name: 'i1' } })
    e2.addProperty({ type: 'string', key: 's1', info: { name: 's1' } })
    const a1 = e1.addAssociation({ key: e2.key }, { key: 'a1', info: { name: 'a1' } })
    a1.addTarget(e3.key)

    a1.schema = { unionType: 'allOf' }

    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    // const dom = new JSDOM(result, { contentType: mime });
    // const schema = dom.window.document;
    // console.log(result);

    // assert.typeOf(data.a1, 'object', 'has the association property');
    // assert.typeOf(data.a1.s1, 'string', 'has the association properties');
    // assert.typeOf(data.a1.i1, 'number', 'has all association targets');
  }).skip()

  test('returns the schema for oneOf union', ({ assert }) => {
    const e3 = d1.addEntity({ key: 'e3', info: { name: 'e3' } })

    e2.addProperty({ type: 'string', key: 's1', info: { name: 's1' } })
    e3.addProperty({ type: 'number', key: 'i1', info: { name: 'i1' } })

    const a1 = e1.addAssociation({ key: e2.key }, { key: 'a1', info: { name: 'a1' } })
    a1.addTarget(e3.key)

    a1.schema = { unionType: 'oneOf' }

    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    // const dom = new JSDOM(result, { contentType: mime });
    // const schema = dom.window.document;
    // console.log(result);

    // assert.typeOf(data.a1, 'object', 'has the association property');
    // assert.typeOf(data.a1.s1, 'string', 'has the association properties');
    // assert.isUndefined(data.a1.i1, 'has no other association target');
  }).skip()

  test('returns the schema for oneOf union with selected shape', ({ assert }) => {
    const e3 = d1.addEntity({ key: 'e3', info: { name: 'e3' } })

    e2.addProperty({ type: 'string', key: 's1', info: { name: 's1' } })
    e3.addProperty({ type: 'number', key: 'i1', info: { name: 'i1' } })

    const a1 = e1.addAssociation({ key: e2.key }, { key: 'a1', info: { name: 'a1' } })
    a1.addTarget(e3.key)

    a1.schema = { unionType: 'oneOf' }

    const result = e1.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    // const dom = new JSDOM(result, { contentType: mime });
    // const schema = dom.window.document;
    // console.log(result);

    // assert.typeOf(data.a1, 'object', 'has the association property');
    // assert.typeOf(data.a1.s1, 'string', 'has the association properties');
    // assert.isUndefined(data.a1.i1, 'has no other association target');
  }).skip()
})

test.group('XML DomainEntity Generator: parents', (group) => {
  let d1: DomainModel
  let e1: DomainEntity
  let e2: DomainEntity

  group.each.setup(() => {
    const ns = new DataDomain()
    d1 = ns.addModel({ key: 'd1', info: { name: 'd1' } })
    e1 = d1.addEntity({ key: 'e1', info: { name: 'e1' } })
    e2 = d1.addEntity({ key: 'e2', info: { name: 'e2' } })
  })

  test('inherits parent properties', ({ assert }) => {
    e1.addProperty({ key: 'p1', type: 'number', info: { name: 'p1' } })
    e2.addParent(e1.key)
    const result = e2.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e2')!
    const p1Element = outer.querySelector('p1')!

    assert.ok(p1Element, 'has the parent property')
  })

  test('inherits parent properties and combines with own', ({ assert }) => {
    e1.addProperty({ key: 'p1', type: 'number', info: { name: 'p1' } })
    e2.addProperty({ key: 'p2', info: { name: 'p2' } })
    e2.addParent(e1.key)

    const result = e2.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e2')!
    const p1Element = outer.querySelector('p1')!
    const p2Element = outer.querySelector('p2')!

    assert.ok(p1Element, 'has the parent property')
    assert.ok(p2Element, 'has own property')

    // assert.typeOf(data.p1, 'number', 'has the parent property');
    // assert.typeOf(data.p2, 'string', 'has own property');
  })

  test('inherits parent properties and combines with own association', ({ assert }) => {
    e1.addProperty({ key: 'p1', type: 'number', info: { name: 'p1' } })
    e2.addProperty({ key: 'p2', info: { name: 'p2' } })
    e2.addParent(e1.key)
    const e3 = d1.addEntity({ key: 'e3', info: { name: 'e3' } })
    e3.addProperty({ type: 'string', key: 'p3', info: { name: 'p3' } })
    e2.addAssociation({ key: e3.key }, { key: 'a1', info: { name: 'a1' } })

    const result = e2.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e2')!
    const p1Element = outer.querySelector('p1')!
    const p2Element = outer.querySelector('p2')!
    const a1Element = outer.querySelector('a1')!

    assert.ok(p1Element, 'has the parent property')
    assert.ok(p2Element, 'has own property')
    assert.ok(a1Element, 'has own association')

    const p3Element = a1Element.querySelector('p3')
    assert.ok(p3Element, 'has association property')

    // assert.typeOf(data.p1, 'number', 'has the parent property');
    // assert.typeOf(data.p2, 'string', 'has own property');
    // assert.typeOf(data.a1, 'object', 'has own association');
    // assert.typeOf(data.a1.p3, 'string', 'has association property');
  })

  test('inherits parent properties with parent association', ({ assert }) => {
    e1.addProperty({ key: 'p1', type: 'number', info: { name: 'p1' } })
    e2.addProperty({ key: 'p2', info: { name: 'p2' } })
    e2.addParent(e1.key)
    const e3 = d1.addEntity({ key: 'e3', info: { name: 'e3' } })
    e3.addProperty({ type: 'string', key: 'p3', info: { name: 'p3' } })
    e1.addAssociation({ key: e3.key }, { key: 'a1', info: { name: 'a1' } })

    const result = e2.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e2')!
    const p1Element = outer.querySelector('p1')!
    const p2Element = outer.querySelector('p2')!
    const a1Element = outer.querySelector('a1')!

    assert.ok(p1Element, 'has the parent property')
    assert.ok(p2Element, 'has own property')
    assert.ok(a1Element, 'has own association')

    const p3Element = a1Element.querySelector('p3')
    assert.ok(p3Element, 'has association property')

    // assert.typeOf(data.p1, 'number', 'has the parent property');
    // assert.typeOf(data.p2, 'string', 'has own property');
    // assert.typeOf(data.a1, 'object', 'has own association');
    // assert.typeOf(data.a1.p3, 'string', 'has association property');
  })

  test('shadows properties', ({ assert }) => {
    e1.addProperty({ type: 'number', info: { name: 'p1' } })
    e2.addProperty({ info: { name: 'p1' } })
    e2.addParent(e1.key)
    const result = e2.toExample(mime) as string
    assert.typeOf(result, 'string', 'result is a string')

    const dom = new JSDOM(result, { contentType: mime })
    const schema = dom.window.document

    const outer = schema.querySelector('e2')!
    const p1Element = outer.querySelector('p1')!
    assert.ok(p1Element, 'has the parent property')
    const value = Number(p1Element.textContent!.trim())
    assert.isNaN(value)
  })
})
