d-r-q/qbit

Entity should be findable by it

Opened this issue · 0 comments

d-r-q commented

Implement property based test for index and fix found bugs.

There is quick scratch of property-based test:

    @Test
    fun `Test`() {
        val rs = RandomSource.default()
        for (i in 0..10) {
            val (schema, idx) = dbArb.sample(rs).value
            val schemaMap = schema.associate { it.name to it }
            val newEntities = (0..1).map {
                entityArb(schema).sample(rs).value
            }
            idx.add(newEntities)

            idx.entities.values.forEach { (_, eavs) ->
                eavs
                    .filter { schemaMap[it.attr]?.list != true && schemaMap[it.attr]?.type != QBytes.code }
                    .forEach { eav ->
                    assertTrue("Cannot find by $eav") {
                        idx.eidsByPred(AttrValuePred(eav.attr, eav.value)).firstOrNull() == eav.gid
                    }
                }
            }
        }
    

    val dataTypeExh = exhaustive(
        listOf(
            QBoolean,
            QByte,
            QInt,
            QLong,
            QString,
            QBytes,
            QRef,
            QGid,
            QBoolean.list(),
            QByte.list(),
            QInt.list(),
            QLong.list(),
            QString.list(),
            QBytes.list(),
            QRef.list(),
            QGid.list()
        )
    )

    val gidArb = arbitrary { rs ->
        Gid(rs.random.nextInt(), rs.random.nextInt())
    }

    val attrArb: Arb<Attr<*>> = Arb.bind(gidArb, Arb.string(), Arb.bool(), dataTypeExh) { gid, name, unique, type ->
        Attr<Any>(gid, name, type.code, unique && !type.isList(), type.isList())
    }

    val schemaArb = arbitrary { rs ->
        val attrsCnt = rs.random.nextInt(0, 10)
        (0..attrsCnt).map {
            attrArb.sample(rs).value
        }
    }

    fun <T : Any> arbValue(rs: RandomSource, type: DataType<T>): T = when (type) {
        is QList<*> -> (0..rs.random.nextInt(0, 10)).map { arbValue(rs, type.itemsType) }.toList()
        QBoolean -> Arb.bool().sample(rs).value
        QByte -> Arb.byte().sample(rs).value
        QInt -> Arb.int().sample(rs).value
        QLong -> Arb.long().sample(rs).value
        QString -> Arb.string().sample(rs).value
        QBytes -> Arb.byteArrays(Arb.int(0, 100), Arb.byte()).sample(rs).value
        QRef -> gidArb.sample(rs).value
        QGid -> gidArb.sample(rs).value
    } as T

    fun entityArb(schema: List<Attr<*>>) = arbitrary { rs ->
        val attrsCnt = rs.random.nextInt(0, schema.size)
        val idxes = (0..attrsCnt).map { rs.random.nextInt(0, schema.size) }.distinct()
        val gid = gidArb.sample(rs).value
        val eavs = idxes.map {
            Eav(
                gid,
                schema[it].name,
                arbValue(rs, DataType.ofCode(schema[it].type) as DataType<Any>)
            )
        }
        gid to eavs
    }

    fun indexArb(schema: List<Attr<*>>): Arb<Index> = arbitrary { rs ->
        val entities = (0..rs.random.nextInt(0, 10))
            .map {
                entityArb(schema).sample(rs).value
            }
        Index().add(entities)
    }

    val dbArb = arbitrary { rs ->
        val schema = schemaArb.sample(rs).value
        val index = indexArb(schema).sample(rs).value
        schema to index
    }

Currently it fails and looks like it's true positive