You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by jd...@apache.org on 2026/04/10 18:01:19 UTC
(grails-core) 03/04: H7 increase test coverge
This is an automated email from the ASF dual-hosted git repository.
jdaugherty pushed a commit to branch 8.0.x-hibernate7
in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 914e07a2328846814fcf3982158e161ad391284e
Author: Walter Duque de Estrada <wb...@mac.com>
AuthorDate: Fri Apr 10 11:40:57 2026 -0500
H7 increase test coverge
---
.../orm/HibernateCriteriaBuilderDirectSpec.groovy | 420 +++++++++++++++++++++
.../orm/hibernate/HibernateDatastoreSpec.groovy | 103 +++++
.../hibernate/SchemaTenantGormEnhancerSpec.groovy | 24 +-
3 files changed, 538 insertions(+), 9 deletions(-)
diff --git a/grails-data-hibernate7/core/src/test/groovy/grails/orm/HibernateCriteriaBuilderDirectSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/grails/orm/HibernateCriteriaBuilderDirectSpec.groovy
index 150708291c..9f93d71ba7 100644
--- a/grails-data-hibernate7/core/src/test/groovy/grails/orm/HibernateCriteriaBuilderDirectSpec.groovy
+++ b/grails-data-hibernate7/core/src/test/groovy/grails/orm/HibernateCriteriaBuilderDirectSpec.groovy
@@ -290,6 +290,426 @@ class HibernateCriteriaBuilderDirectSpec extends HibernateGormDatastoreSpec {
results[0].firstName == "Fred"
}
+ void "test properties and projections methods"() {
+ when:
+ def b = new HibernateCriteriaBuilder(DirectAccount, manager.hibernateDatastore.sessionFactory, manager.hibernateDatastore)
+
+ then:
+ b.property("firstName")
+ b.distinct("lastName")
+ b.avg("balance")
+ b.projections() != null
+ b.closeSession()
+ }
+
+ void "test boolean flags and setter getter methods"() {
+ when:
+ def b = new HibernateCriteriaBuilder(DirectAccount, manager.hibernateDatastore.sessionFactory, manager.hibernateDatastore)
+ b.uniqueResult = true
+ b.distinct = true
+ b.count = true
+ b.paginationEnabledList = true
+ b.scroll = true
+
+ then:
+ b.isUniqueResult() == true
+ b.isDistinct() == true
+ b.isCount() == true
+ b.isPaginationEnabledList() == true
+ b.isScroll() == true
+ b.getInstance() == null
+ b.getCriteriaBuilder() != null
+ b.getSessionFactory() != null
+ b.getHibernateQuery() != null
+ b.isParticipate() == true
+ b.getDefaultFlushMode() == org.grails.orm.hibernate.GrailsHibernateTemplate.FLUSH_AUTO
+
+ when:
+ b.setDefaultFlushMode(1)
+ then:
+ b.getDefaultFlushMode() == 1
+
+ when:
+ b.lock(true)
+ b.cache(true)
+ b.maxResults(10)
+ then:
+ noExceptionThrown()
+
+ cleanup:
+ b.closeSession()
+ }
+
+ void "test alias and join methods"() {
+ when:
+ def b = new HibernateCriteriaBuilder(DirectAccount, manager.hibernateDatastore.sessionFactory, manager.hibernateDatastore)
+ b.join("transactions")
+ b.join("transactions", jakarta.persistence.criteria.JoinType.INNER)
+ b.select("transactions")
+ b.createAlias("transactions", "t")
+ b.createAlias("transactions", "t2", 1) // LEFT
+ b.createAlias("transactions", "t3", 2) // RIGHT
+ b.createAlias("transactions", "t4", 3) // INNER
+
+ then:
+ noExceptionThrown()
+
+ cleanup:
+ b.closeSession()
+ }
+
+ void "test exception handling"() {
+ when:
+ def b = new HibernateCriteriaBuilder(DirectAccount, manager.hibernateDatastore.sessionFactory, manager.hibernateDatastore)
+ b.throwRuntimeException(new RuntimeException("test exception"))
+
+ then:
+ thrown(RuntimeException)
+ }
+
+ void "test missing criterion methods"() {
+ when:
+ def b = new HibernateCriteriaBuilder(DirectAccount, manager.hibernateDatastore.sessionFactory, manager.hibernateDatastore)
+ b.eqProperty("firstName", "lastName")
+ b.neProperty("firstName", "lastName")
+ b.gtProperty("firstName", "lastName")
+ b.geProperty("firstName", "lastName")
+ b.ltProperty("firstName", "lastName")
+ b.leProperty("firstName", "lastName")
+
+ b.allEq(["firstName": "Fred"])
+ b.idEq(1L)
+ b.idEquals(1L)
+
+ b.isEmpty("firstName")
+ b.isNotEmpty("firstName")
+ b.isNull("firstName")
+ b.isNotNull("firstName")
+
+ b.like("firstName", "Fre%")
+ b.ilike("firstName", "fre%")
+ b.rlike("firstName", ".*")
+
+ b.in("firstName", ["Fred", "Barney"])
+ b.inList("firstName", ["Fred", "Barney"])
+ b.inList("firstName", "Fred", "Barney")
+ b.in("firstName", "Fred", "Barney")
+ b.notIn("firstName") { eq("firstName", "Wilma") }
+
+ b.gt("balance", 100)
+ b.ge("balance", 100)
+ b.gte("balance", 100)
+ b.lt("balance", 100)
+ b.le("balance", 100)
+ b.lte("balance", 100)
+ b.ne("balance", 100)
+ b.between("balance", 100, 200)
+
+ b.sizeEq("transactions", 1)
+ b.sizeGt("transactions", 1)
+ b.sizeGe("transactions", 1)
+ b.sizeLt("transactions", 1)
+ b.sizeLe("transactions", 1)
+ b.sizeNe("transactions", 1)
+
+ b.order("firstName")
+ b.order("lastName", "desc")
+ b.firstResult(0)
+
+ b.and { eq("firstName", "Fred") }
+ b.or { eq("firstName", "Fred") }
+ b.not { eq("firstName", "Fred") }
+
+ then:
+ noExceptionThrown()
+
+ cleanup:
+ b.closeSession()
+ }
+
+ void "test subqueries with closures"() {
+ when:
+ def b = new HibernateCriteriaBuilder(DirectAccount, manager.hibernateDatastore.sessionFactory, manager.hibernateDatastore)
+
+ b.eqAll("balance") { eq("balance", 100) }
+ b.gtAll("balance") { eq("balance", 100) }
+ b.geAll("balance") { eq("balance", 100) }
+ b.ltAll("balance") { eq("balance", 100) }
+ b.leAll("balance") { eq("balance", 100) }
+
+ b.gtSome("balance") { eq("balance", 100) }
+ b.geSome("balance") { eq("balance", 100) }
+ b.ltSome("balance") { eq("balance", 100) }
+ b.leSome("balance") { eq("balance", 100) }
+
+ b.in("balance") { eq("balance", 100) }
+ b.inList("balance") { eq("balance", 100) }
+ b.notIn("balance") { eq("balance", 100) }
+
+ then:
+ noExceptionThrown()
+
+ cleanup:
+ b.closeSession()
+ }
+
+ void "test subqueries with QueryableCriteria"() {
+ when:
+ def b = new HibernateCriteriaBuilder(DirectAccount, manager.hibernateDatastore.sessionFactory, manager.hibernateDatastore)
+ def criteria = new grails.gorm.DetachedCriteria(DirectAccount).build { eq("balance", 100) }
+
+ b.eqAll("balance", criteria)
+ b.gtAll("balance", criteria)
+ b.geAll("balance", criteria)
+ b.ltAll("balance", criteria)
+ b.leAll("balance", criteria)
+
+ b.gtSome("balance", criteria)
+ b.geSome("balance", criteria)
+ b.ltSome("balance", criteria)
+ b.leSome("balance", criteria)
+
+ b.in("balance", criteria)
+ b.inList("balance", criteria)
+ b.notIn("balance", criteria)
+
+ b.exists(criteria)
+ b.notExists(criteria)
+
+ then:
+ noExceptionThrown()
+
+ cleanup:
+ b.closeSession()
+ }
+
+ void "test execution methods"() {
+ when:
+ def b = new HibernateCriteriaBuilder(DirectAccount, manager.hibernateDatastore.sessionFactory, manager.hibernateDatastore)
+ b.list { eq("firstName", "Fred") }
+ b.list([max: 10]) { eq("firstName", "Fred") }
+ b.listDistinct { eq("firstName", "Fred") }
+ b.get { eq("firstName", "Fred") }
+ try { b.scroll { eq("firstName", "Fred") } } catch(UnsupportedOperationException e) { /* expected in this mock environment */ }
+ b.list()
+
+ then:
+ noExceptionThrown()
+
+ cleanup:
+ b.closeSession()
+ }
+
+ void "test properties and projections methods"() {
+ when:
+ def b = new HibernateCriteriaBuilder(DirectAccount, manager.hibernateDatastore.sessionFactory, manager.hibernateDatastore)
+
+ then:
+ b.property("firstName")
+ b.distinct("lastName")
+ b.avg("balance")
+ b.projections() != null
+ b.closeSession()
+ }
+
+ void "test boolean flags and setter getter methods"() {
+ when:
+ def b = new HibernateCriteriaBuilder(DirectAccount, manager.hibernateDatastore.sessionFactory, manager.hibernateDatastore)
+ b.uniqueResult = true
+ b.distinct = true
+ b.count = true
+ b.paginationEnabledList = true
+ b.scroll = true
+
+ then:
+ b.isUniqueResult() == true
+ b.isDistinct() == true
+ b.isCount() == true
+ b.isPaginationEnabledList() == true
+ b.isScroll() == true
+ b.getInstance() == null
+ b.getCriteriaBuilder() != null
+ b.getSessionFactory() != null
+ b.getHibernateQuery() != null
+ b.isParticipate() == true
+ b.getDefaultFlushMode() == org.grails.orm.hibernate.GrailsHibernateTemplate.FLUSH_AUTO
+
+ when:
+ b.setDefaultFlushMode(1)
+ then:
+ b.getDefaultFlushMode() == 1
+
+ when:
+ b.lock(true)
+ b.cache(true)
+ b.maxResults(10)
+ then:
+ noExceptionThrown()
+
+ cleanup:
+ b.closeSession()
+ }
+
+ void "test alias and join methods"() {
+ when:
+ def b = new HibernateCriteriaBuilder(DirectAccount, manager.hibernateDatastore.sessionFactory, manager.hibernateDatastore)
+ b.join("transactions")
+ b.join("transactions", jakarta.persistence.criteria.JoinType.INNER)
+ b.select("transactions")
+ b.createAlias("transactions", "t")
+ b.createAlias("transactions", "t2", 1) // LEFT
+ b.createAlias("transactions", "t3", 2) // RIGHT
+ b.createAlias("transactions", "t4", 3) // INNER
+
+ then:
+ noExceptionThrown()
+
+ cleanup:
+ b.closeSession()
+ }
+
+ void "test exception handling"() {
+ when:
+ def b = new HibernateCriteriaBuilder(DirectAccount, manager.hibernateDatastore.sessionFactory, manager.hibernateDatastore)
+ b.throwRuntimeException(new RuntimeException("test exception"))
+
+ then:
+ thrown(RuntimeException)
+ }
+
+ void "test missing criterion methods"() {
+ when:
+ def b = new HibernateCriteriaBuilder(DirectAccount, manager.hibernateDatastore.sessionFactory, manager.hibernateDatastore)
+ b.eqProperty("firstName", "lastName")
+ b.neProperty("firstName", "lastName")
+ b.gtProperty("firstName", "lastName")
+ b.geProperty("firstName", "lastName")
+ b.ltProperty("firstName", "lastName")
+ b.leProperty("firstName", "lastName")
+
+ b.allEq(["firstName": "Fred"])
+ b.idEq(1L)
+ b.idEquals(1L)
+
+ b.isEmpty("firstName")
+ b.isNotEmpty("firstName")
+ b.isNull("firstName")
+ b.isNotNull("firstName")
+
+ b.like("firstName", "Fre%")
+ b.ilike("firstName", "fre%")
+ b.rlike("firstName", ".*")
+
+ b.in("firstName", ["Fred", "Barney"])
+ b.inList("firstName", ["Fred", "Barney"])
+ b.inList("firstName", "Fred", "Barney")
+ b.in("firstName", "Fred", "Barney")
+ b.notIn("firstName") { eq("firstName", "Wilma") }
+
+ b.gt("balance", 100)
+ b.ge("balance", 100)
+ b.gte("balance", 100)
+ b.lt("balance", 100)
+ b.le("balance", 100)
+ b.lte("balance", 100)
+ b.ne("balance", 100)
+ b.between("balance", 100, 200)
+
+ b.sizeEq("transactions", 1)
+ b.sizeGt("transactions", 1)
+ b.sizeGe("transactions", 1)
+ b.sizeLt("transactions", 1)
+ b.sizeLe("transactions", 1)
+ b.sizeNe("transactions", 1)
+
+ b.order("firstName")
+ b.order("lastName", "desc")
+ b.firstResult(0)
+
+ b.and { eq("firstName", "Fred") }
+ b.or { eq("firstName", "Fred") }
+ b.not { eq("firstName", "Fred") }
+
+ then:
+ noExceptionThrown()
+
+ cleanup:
+ b.closeSession()
+ }
+
+ void "test subqueries with closures"() {
+ when:
+ def b = new HibernateCriteriaBuilder(DirectAccount, manager.hibernateDatastore.sessionFactory, manager.hibernateDatastore)
+
+ b.eqAll("balance") { eq("balance", 100) }
+ b.gtAll("balance") { eq("balance", 100) }
+ b.geAll("balance") { eq("balance", 100) }
+ b.ltAll("balance") { eq("balance", 100) }
+ b.leAll("balance") { eq("balance", 100) }
+
+ b.gtSome("balance") { eq("balance", 100) }
+ b.geSome("balance") { eq("balance", 100) }
+ b.ltSome("balance") { eq("balance", 100) }
+ b.leSome("balance") { eq("balance", 100) }
+
+ b.in("balance") { eq("balance", 100) }
+ b.inList("balance") { eq("balance", 100) }
+ b.notIn("balance") { eq("balance", 100) }
+
+ then:
+ noExceptionThrown()
+
+ cleanup:
+ b.closeSession()
+ }
+
+ void "test subqueries with QueryableCriteria"() {
+ when:
+ def b = new HibernateCriteriaBuilder(DirectAccount, manager.hibernateDatastore.sessionFactory, manager.hibernateDatastore)
+ def criteria = new grails.gorm.DetachedCriteria(DirectAccount).build { eq("balance", 100) }
+
+ b.eqAll("balance", criteria)
+ b.gtAll("balance", criteria)
+ b.geAll("balance", criteria)
+ b.ltAll("balance", criteria)
+ b.leAll("balance", criteria)
+
+ b.gtSome("balance", criteria)
+ b.geSome("balance", criteria)
+ b.ltSome("balance", criteria)
+ b.leSome("balance", criteria)
+
+ b.in("balance", criteria)
+ b.inList("balance", criteria)
+ b.notIn("balance", criteria)
+
+ b.exists(criteria)
+ b.notExists(criteria)
+
+ then:
+ noExceptionThrown()
+
+ cleanup:
+ b.closeSession()
+ }
+
+ void "test execution methods"() {
+ when:
+ def b = new HibernateCriteriaBuilder(DirectAccount, manager.hibernateDatastore.sessionFactory, manager.hibernateDatastore)
+ b.list { eq("firstName", "Fred") }
+ b.list([max: 10]) { eq("firstName", "Fred") }
+ b.listDistinct { eq("firstName", "Fred") }
+ b.get { eq("firstName", "Fred") }
+ try { b.scroll { eq("firstName", "Fred") } } catch(UnsupportedOperationException e) { /* expected in this mock environment */ }
+ b.list()
+
+ then:
+ noExceptionThrown()
+
+ cleanup:
+ b.closeSession()
+ }
+
// ─── Comparison predicates ─────────────────────────────────────────────
def "eq(String, Object) delegates and returns this"() {
diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateDatastoreSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateDatastoreSpec.groovy
index f792084283..9a2a9302bd 100644
--- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateDatastoreSpec.groovy
+++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/HibernateDatastoreSpec.groovy
@@ -248,6 +248,109 @@ class HibernateDatastoreSpec extends HibernateGormDatastoreSpec {
expect:
datastore.getMetadata() != null
}
+
+ void "test toString returns datasource name"() {
+ expect:
+ datastore.toString() == "HibernateDatastore: default"
+ }
+
+ void "test withSession and withNewSession for connectionName"() {
+ when:
+ def result1 = datastore.withSession("default") { session -> return "session1" }
+ def result2 = datastore.withNewSession("default") { session -> return "session2" }
+
+ then:
+ result1 == "session1"
+ result2 == "session2"
+ }
+
+ void "test withNewSession with tenantId for non-DATABASE multitenancy"() {
+ when:
+ def result = datastore.withNewSession((Serializable) "someTenant") { session -> return "sessionTenant" }
+
+ then:
+ result == "sessionTenant"
+ }
+
+ void "test close handles exception"() {
+ given:
+ def ds = new HibernateDatastore(Collections.singletonMap(Settings.SETTING_DB_CREATE, "create-drop"), GHUBook) {
+ @Override
+ void destroy() throws Exception {
+ throw new RuntimeException("destroy failed")
+ }
+ }
+
+ when:
+ ds.close()
+
+ then:
+ noExceptionThrown()
+ }
+
+ void "test constructors"() {
+ given:
+ def configMap = new HashMap<>(manager.grailsConfig)
+ configMap.put("dataSource.url", "jdbc:h2:mem:grailsDB-constructors;LOCK_TIMEOUT=10000") // avoid clash with datastore
+ org.springframework.core.env.PropertyResolver propertyResolver = org.grails.datastore.mapping.core.DatastoreUtils.createPropertyResolver(configMap)
+ def dataSource = datastore.dataSource
+ def eventPublisher = datastore.applicationEventPublisher as org.grails.datastore.gorm.events.ConfigurableApplicationEventPublisher
+ Package pkg = String.getPackage()
+
+ when: "Constructor with EventPublisher and Classes"
+ def ds1 = new HibernateDatastore(propertyResolver, eventPublisher, GHUBook)
+ then:
+ ds1 != null
+ ds1.close()
+
+ when: "Constructor with DataSource, EventPublisher and Classes"
+ def ds2 = new HibernateDatastore(dataSource, propertyResolver, eventPublisher, GHUBook)
+ then:
+ ds2 != null
+ ds2.close()
+
+ when: "Constructor with EventPublisher and Packages"
+ def ds3 = new HibernateDatastore(propertyResolver, eventPublisher, pkg)
+ then:
+ ds3 != null
+ ds3.close()
+
+ when: "Constructor with DataSource, EventPublisher and Packages"
+ def ds4 = new HibernateDatastore(dataSource, propertyResolver, eventPublisher, pkg)
+ then:
+ ds4 != null
+ ds4.close()
+
+ when: "Constructor with Configuration Map and Packages"
+ def ds5 = new HibernateDatastore(configMap, pkg)
+ then:
+ ds5 != null
+ ds5.close()
+
+ when: "Constructor with Packages only"
+ def ds6 = new HibernateDatastore(pkg)
+ then:
+ ds6 != null
+ ds6.close()
+
+ when: "Constructor with MappingContext, SessionFactory, PropertyResolver, ApplicationContext, dataSourceName"
+ def ds7 = new HibernateDatastore(datastore.mappingContext, datastore.sessionFactory, propertyResolver, datastore.applicationContext, "default")
+ then:
+ ds7 != null
+
+ when: "Constructor with MappingContext, SessionFactory, PropertyResolver"
+ def ds8 = new HibernateDatastore(datastore.mappingContext, datastore.sessionFactory, propertyResolver)
+ then:
+ ds8 != null
+ }
+
+ void "test setMessageSource"() {
+ when:
+ datastore.setMessageSource(Mock(org.springframework.context.MessageSource))
+
+ then:
+ noExceptionThrown()
+ }
}
@Entity
diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/SchemaTenantGormEnhancerSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/SchemaTenantGormEnhancerSpec.groovy
index c7b7565d94..487ed0ffc6 100644
--- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/SchemaTenantGormEnhancerSpec.groovy
+++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/SchemaTenantGormEnhancerSpec.groovy
@@ -32,7 +32,7 @@ import spock.lang.Shared
import spock.lang.Specification
/**
- * Verifies the behaviour of {@link HibernateDatastore.SchemaTenantGormEnhancer}
+ * Verifies the behaviour of SchemaTenantGormEnhancer
* which is instantiated when the datastore runs in SCHEMA multi-tenancy mode.
*
* Because Hibernate infrastructure classes are final / sealed, we drive the
@@ -45,7 +45,7 @@ class SchemaTenantGormEnhancerSpec extends Specification {
HibernateDatastore datastore
@Shared
- HibernateDatastore.SchemaTenantGormEnhancer enhancer
+ def enhancer
void setupSpec() {
System.setProperty(SystemPropertyTenantResolver.PROPERTY_NAME, "")
@@ -60,7 +60,7 @@ class SchemaTenantGormEnhancerSpec extends Specification {
'hibernate.hbm2ddl.auto' : 'create',
]
datastore = new HibernateDatastore(DatastoreUtils.createPropertyResolver(config), SchemaTenantBook)
- enhancer = datastore.gormEnhancer as HibernateDatastore.SchemaTenantGormEnhancer
+ enhancer = datastore.gormEnhancer
}
void cleanupSpec() {
@@ -70,7 +70,7 @@ class SchemaTenantGormEnhancerSpec extends Specification {
void "gormEnhancer is an instance of SchemaTenantGormEnhancer in SCHEMA mode"() {
expect:
- enhancer instanceof HibernateDatastore.SchemaTenantGormEnhancer
+ enhancer.getClass().name == "org.grails.orm.hibernate.HibernateDatastore\$SchemaTenantGormEnhancer"
}
void "allQualifiers includes tenant IDs from AllTenantsResolver for MultiTenant entity"() {
@@ -112,15 +112,21 @@ class SchemaTenantGormEnhancerSpec extends Specification {
}
void "SchemaTenantGormEnhancer is a public static nested class of HibernateDatastore"() {
+ given:
+ def enhancerClass = Class.forName("org.grails.orm.hibernate.HibernateDatastore\$SchemaTenantGormEnhancer")
+
expect:
- HibernateDatastore.SchemaTenantGormEnhancer.enclosingClass == HibernateDatastore
- Modifier.isStatic(HibernateDatastore.SchemaTenantGormEnhancer.modifiers)
- Modifier.isPublic(HibernateDatastore.SchemaTenantGormEnhancer.modifiers)
+ enhancerClass.enclosingClass == HibernateDatastore
+ Modifier.isStatic(enhancerClass.modifiers)
+ Modifier.isPublic(enhancerClass.modifiers)
}
void "SchemaTenantGormEnhancer extends HibernateGormEnhancer"() {
+ given:
+ def enhancerClass = Class.forName("org.grails.orm.hibernate.HibernateDatastore\$SchemaTenantGormEnhancer")
+
expect:
- HibernateGormEnhancer.isAssignableFrom(HibernateDatastore.SchemaTenantGormEnhancer)
+ HibernateGormEnhancer.isAssignableFrom(enhancerClass)
}
// -------------------------------------------------------------------------
@@ -142,7 +148,7 @@ class SchemaTenantGormEnhancerSpec extends Specification {
]
HibernateDatastore schemaDs = new HibernateDatastore(
DatastoreUtils.createPropertyResolver(config), SchemaTenantBook)
- def schemaEnhancer = schemaDs.gormEnhancer as HibernateDatastore.SchemaTenantGormEnhancer
+ def schemaEnhancer = schemaDs.gormEnhancer
def entity = schemaDs.getMappingContext().getPersistentEntity(SchemaTenantBook.name)
when: "allQualifiers resolves via schemaHandler (H2 returns no custom schemas)"