Skip to content

Commit 0372233

Browse files
authored
closes #66 (#67)
* closes #66
1 parent 4ccca89 commit 0372233

File tree

8 files changed

+134
-9
lines changed

8 files changed

+134
-9
lines changed

.github/badges/jacoco.svg

Lines changed: 1 addition & 1 deletion
Loading

src/main/kotlin/org/xpathqs/core/reflection/ReflectionExtensions.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,4 +182,13 @@ internal fun Any.getInnerClassMember(): Any? {
182182
}
183183
f?.isAccessible = true
184184
return f?.get(this)
185+
}
186+
187+
/**
188+
* Sets the <pre>base</pre> to the [BaseSelector] via reflection
189+
*/
190+
internal fun <T : BaseSelector> T.setAnnotations(annotations: Collection<Annotation>): T {
191+
SelectorReflection(this)
192+
.setAnnotations(annotations)
193+
return this
185194
}

src/main/kotlin/org/xpathqs/core/reflection/SelectorParser.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import org.xpathqs.core.selector.base.ISelector
3030
/**
3131
* Class for initializing Selectors names and structure via Reflection
3232
* @sample org.xpathqs.core.reflection.parser.ObjectWithBaseTest
33-
* @sample org.xpathqs.core.reflection.parser.ObjectWithoutBase
33+
* @sample org.xpathqs.core.reflection.parser.ObjectWithoutBaseTest
3434
* @sample org.xpathqs.core.reflection.parser.ObjectWithBaseAndInnerObjectTest
3535
*/
3636
internal class SelectorParser(
@@ -48,15 +48,17 @@ internal class SelectorParser(
4848

4949
rootObj.setBase(base)
5050
rootObj.setName(baseName + rootObj::class.simpleName!!)
51+
rootObj.setAnnotations(rootObj::class.annotations.toList())
5152
rootObj.freeze()
5253

5354
rootObj.children = srf.innerSelectors
5455

5556
srf.innerSelectorFields.forEach {
5657
it.isAccessible = true
5758
val sel = it.get(rootObj) as BaseSelector
58-
sel.setName(rootObj.name + "." + it.name)
5959
sel.setBase(rootObj)
60+
sel.setName(rootObj.name + "." + it.name)
61+
sel.setAnnotations(it.annotations.toList())
6062
sel.freeze()
6163

6264
if (sel is Block) {

src/main/kotlin/org/xpathqs/core/reflection/SelectorReflection.kt

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,17 @@ internal class SelectorReflection(
5757
/**
5858
* Set <pre>name</pre> field of the [obj]
5959
*/
60-
fun setName(value: String) = setProp("name", value)
60+
fun setName(value: String) = setProp(BaseSelector::name.name, value)
6161

6262
/**
6363
* Set <pre>base</pre> field of the [obj]
6464
*/
65-
fun setBase(value: ISelector) = setProp("base", value)
65+
fun setBase(value: ISelector) = setProp(BaseSelector::base.name, value)
6666

6767
/**
6868
* Set <pre>props</pre> field of the [obj]
6969
*/
70-
fun setProps(value: BaseSelectorProps) = setProp("props", value)
70+
fun setProps(value: BaseSelectorProps) = setProp(BaseSelector::props.name, value)
7171

7272
/**
7373
* Set <pre>props.args</pre> field of the [obj]
@@ -77,10 +77,17 @@ internal class SelectorReflection(
7777
/**
7878
* Mark [obj] as freeze
7979
*/
80-
fun freeze() = setProp("state", SelectorState.FREEZE)
80+
fun freeze() = setProp(BaseSelector::state.name, SelectorState.FREEZE)
8181

8282
/**
8383
* Mark [obj] as cloned
8484
*/
85-
fun cloned() = setProp("state", SelectorState.CLONED)
85+
fun cloned() = setProp(BaseSelector::state.name, SelectorState.CLONED)
86+
87+
/**
88+
* Set [BaseSelector.annotations] field of the [BaseSelector]
89+
* @param annotations collection of annotation classes provided via reflection
90+
*/
91+
fun setAnnotations(annotations: Collection<Annotation>)
92+
= setProp(BaseSelector::annotations.name, annotations)
8693
}

src/main/kotlin/org/xpathqs/core/selector/base/BaseSelector.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import org.xpathqs.core.selector.NullSelector
3030
* @param base link to the root element
3131
* @param name name of the selector (used for logging purposes)
3232
* @param props properties for building xpath queries
33+
* @param annotations list of annotations for selector
3334
*/
3435
abstract class BaseSelector(
3536
internal val state: SelectorState = SelectorState.INIT,
@@ -38,6 +39,7 @@ abstract class BaseSelector(
3839
override val name: String = "",
3940

4041
internal open val props: BaseSelectorProps = BaseSelectorProps(),
42+
val annotations: Collection<Annotation> = emptyList()
4143
) : ISelector {
4244

4345
/**

src/main/kotlin/org/xpathqs/core/selector/extensions/SelectorCoreExtensions.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ fun <T : BaseSelector> T.deepClone(): T {
5656

5757
newObj.setName(this.name)
5858
newObj.setBase(this.base)
59+
newObj.setAnnotations(this.annotations)
5960
newObj.setProps(this.props.clone())
6061

6162
newObj.cloned()
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (c) 2021 Nikita A. Chegodaev
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
23+
package org.xpathqs.core.reflection
24+
25+
import assertk.assertThat
26+
import assertk.assertions.hasSize
27+
import org.junit.jupiter.api.BeforeAll
28+
import org.junit.jupiter.api.Test
29+
import org.xpathqs.core.selector.Block
30+
import org.xpathqs.core.selector.extensions.get
31+
import org.xpathqs.core.util.SelectorFactory.tagSelector
32+
33+
@Target(
34+
AnnotationTarget.CLASS,
35+
AnnotationTarget.FIELD
36+
)
37+
@Retention(AnnotationRetention.RUNTIME)
38+
annotation class TestAnnotation1
39+
40+
@Target(
41+
AnnotationTarget.CLASS,
42+
AnnotationTarget.FIELD
43+
)
44+
@Retention(AnnotationRetention.RUNTIME)
45+
annotation class TestAnnotation2
46+
47+
@TestAnnotation1
48+
object PageWithAnnotations : Block() {
49+
@TestAnnotation2
50+
val s1 = tagSelector()
51+
val s2 = tagSelector()
52+
53+
@TestAnnotation2
54+
@TestAnnotation1
55+
val s3 = tagSelector()
56+
}
57+
58+
class SelectorAnnotationsTest {
59+
60+
@Test
61+
fun checkBlock() {
62+
assertThat(PageWithAnnotations.annotations)
63+
.hasSize(1)
64+
}
65+
66+
@Test
67+
fun checkSelector() {
68+
assertThat(PageWithAnnotations.s1.annotations)
69+
.hasSize(1)
70+
}
71+
72+
@Test
73+
fun checkSelectorWithoutAnnotation() {
74+
assertThat(PageWithAnnotations.s2.annotations)
75+
.hasSize(0)
76+
}
77+
78+
@Test
79+
fun checkSelectorWithTwoAnnotation() {
80+
assertThat(PageWithAnnotations.s3.annotations)
81+
.hasSize(2)
82+
}
83+
84+
@Test
85+
fun annotationsShouldBeCloned() {
86+
assertThat(PageWithAnnotations.s3[2].annotations)
87+
.hasSize(2)
88+
}
89+
90+
companion object {
91+
@JvmStatic
92+
@BeforeAll
93+
fun init() {
94+
SelectorParser(PageWithAnnotations).parse()
95+
}
96+
}
97+
}

src/test/kotlin/org/xpathqs/core/reflection/SelectorReflectionFieldsTest.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,18 @@ package org.xpathqs.core.reflection
2525
import assertk.assertThat
2626
import assertk.assertions.containsExactlyInAnyOrder
2727
import org.junit.jupiter.api.Test
28+
import org.xpathqs.core.selector.base.BaseSelector
2829
import org.xpathqs.core.selector.selector.Selector
2930

3031
internal class SelectorReflectionFieldsTest {
3132

32-
private val selectorFields = arrayOf("state", "base", "props", "name")
33+
private val selectorFields = arrayOf(
34+
BaseSelector::state.name,
35+
BaseSelector::base.name,
36+
BaseSelector::props.name,
37+
BaseSelector::name.name,
38+
BaseSelector::annotations.name,
39+
)
3340

3441
@Test
3542
fun declaredFieldsForSelector() {

0 commit comments

Comments
 (0)