Skip to content

Commit 2de5cbe

Browse files
committed
added StackTraceElementProxyTest, minor edits to AGENTS.md
Signed-off-by: ceki <ceki@qos.ch>
1 parent 0e9b927 commit 2de5cbe

2 files changed

Lines changed: 159 additions & 0 deletions

File tree

AGENTS.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,11 @@
1313
compatibility, especially changes in interfaces or super classes.
1414

1515
Follow these rules at all times.
16+
17+
Maven can be located via the value of the $MAVEN_HOME environment variable.
18+
Java can ve located via the value of the $JAVA_HOME environment variable.
19+
20+
Indicate whether these values are accessible or not.
21+
22+
If valid, always use the values of these environment variables to
23+
locate Maven and Java.
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/*
2+
* Logback: the reliable, generic, fast and flexible logging framework.
3+
* Copyright (C) 1999-2026, QOS.ch. All rights reserved.
4+
*
5+
* This program and the accompanying materials are dual-licensed under
6+
* either the terms of the Eclipse Public License v2.0 as published by
7+
* the Eclipse Foundation
8+
*
9+
* or (per the licensee's choosing)
10+
*
11+
* under the terms of the GNU Lesser General Public License version 2.1
12+
* as published by the Free Software Foundation.
13+
*/
14+
package ch.qos.logback.classic.spi;
15+
16+
import ch.qos.logback.classic.ClassicConstants;
17+
import org.junit.jupiter.api.Test;
18+
19+
import java.io.ByteArrayInputStream;
20+
import java.io.ByteArrayOutputStream;
21+
import java.io.IOException;
22+
import java.io.ObjectInputStream;
23+
import java.io.ObjectOutputStream;
24+
25+
import static org.junit.jupiter.api.Assertions.assertEquals;
26+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
27+
import static org.junit.jupiter.api.Assertions.assertNotNull;
28+
import static org.junit.jupiter.api.Assertions.assertSame;
29+
import static org.junit.jupiter.api.Assertions.assertThrows;
30+
import static org.junit.jupiter.api.Assertions.assertTrue;
31+
32+
public class StackTraceElementProxyTest {
33+
34+
@Test
35+
public void nullStackTraceElementIsReplacedByNASubstitute() {
36+
StackTraceElementProxy step = new StackTraceElementProxy(null);
37+
38+
assertNotNull(step.getStackTraceElement());
39+
assertSame(StackTraceElementProxy.NA_SUBSTITUTE, step.getStackTraceElement());
40+
41+
StackTraceElement ste = step.getStackTraceElement();
42+
assertEquals(ClassicConstants.DECLARING_CLASS_NA, ste.getClassName());
43+
assertEquals(ClassicConstants.METHOD_NAME_NA, ste.getMethodName());
44+
assertEquals(ClassicConstants.FILENAME_NA, ste.getFileName());
45+
assertEquals(ClassicConstants.LINE_NUMBER_NA, ste.getLineNumber());
46+
}
47+
48+
@Test
49+
public void getSTEAsStringWorksWithNullInput() {
50+
StackTraceElementProxy step = new StackTraceElementProxy(null);
51+
String steAsString = step.getSTEAsString();
52+
assertNotNull(steAsString);
53+
assertTrue(steAsString.startsWith("at "));
54+
assertTrue(steAsString.contains(ClassicConstants.DECLARING_CLASS_NA));
55+
assertTrue(steAsString.contains(ClassicConstants.METHOD_NAME_NA));
56+
}
57+
58+
@Test
59+
public void toStringWorksWithNullInput() {
60+
StackTraceElementProxy step = new StackTraceElementProxy(null);
61+
assertEquals(step.getSTEAsString(), step.toString());
62+
}
63+
64+
@Test
65+
public void hashCodeAndEqualsWorkWithNullInput() {
66+
StackTraceElementProxy step1 = new StackTraceElementProxy(null);
67+
StackTraceElementProxy step2 = new StackTraceElementProxy(null);
68+
69+
assertEquals(step1, step2);
70+
assertEquals(step1.hashCode(), step2.hashCode());
71+
72+
StackTraceElement realSTE = new StackTraceElement("com.example.Foo", "bar", "Foo.java", 42);
73+
StackTraceElementProxy step3 = new StackTraceElementProxy(realSTE);
74+
75+
assertNotEquals(step1, step3);
76+
assertNotEquals(step1.hashCode(), step3.hashCode());
77+
}
78+
79+
@Test
80+
public void equalsHandlesNullAndDifferentClass() {
81+
StackTraceElementProxy step = new StackTraceElementProxy(null);
82+
assertNotEquals(null, step);
83+
assertEquals(step, step);
84+
}
85+
86+
@Test
87+
public void normalNonNullStackTraceElement() {
88+
StackTraceElement realSTE = new StackTraceElement("com.example.MyClass", "doSomething", "MyClass.java", 123);
89+
StackTraceElementProxy step = new StackTraceElementProxy(realSTE);
90+
91+
assertSame(realSTE, step.getStackTraceElement());
92+
assertTrue(step.getSTEAsString().startsWith("at com.example.MyClass.doSomething(MyClass.java:123)"));
93+
assertEquals(step.getSTEAsString(), step.toString());
94+
}
95+
96+
@Test
97+
public void classPackagingData() {
98+
StackTraceElementProxy step = new StackTraceElementProxy(null);
99+
100+
assertEquals(null, step.getClassPackagingData());
101+
102+
ClassPackagingData cpd = new ClassPackagingData("some.jar", "1.0", true);
103+
step.setClassPackagingData(cpd);
104+
assertSame(cpd, step.getClassPackagingData());
105+
106+
// second set must throw
107+
assertThrows(IllegalStateException.class, () -> step.setClassPackagingData(new ClassPackagingData("x", "y")));
108+
109+
// packaging data affects equals
110+
StackTraceElementProxy step2 = new StackTraceElementProxy(null);
111+
step2.setClassPackagingData(new ClassPackagingData("some.jar", "1.0", true));
112+
assertEquals(step, step2);
113+
114+
StackTraceElementProxy step3 = new StackTraceElementProxy(null);
115+
step3.setClassPackagingData(new ClassPackagingData("other.jar", "2.0", false));
116+
assertNotEquals(step, step3);
117+
}
118+
119+
@Test
120+
public void serializationRoundTripPreservesBehavior() throws IOException, ClassNotFoundException {
121+
// normal STE case
122+
StackTraceElement realSTE = new StackTraceElement("p.q.R", "m", "R.java", 7);
123+
StackTraceElementProxy original = new StackTraceElementProxy(realSTE);
124+
original.setClassPackagingData(new ClassPackagingData("loc", "ver"));
125+
String originalAsString = original.getSTEAsString(); // force cache of transient
126+
127+
StackTraceElementProxy deserialized = roundTripSerialize(original);
128+
assertEquals(original, deserialized);
129+
assertEquals(originalAsString, deserialized.getSTEAsString());
130+
assertEquals(original.getClassPackagingData(), deserialized.getClassPackagingData()); // deserialized instance, use equals not same
131+
132+
// null STE (NA_SUBSTITUTE) case
133+
StackTraceElementProxy originalNull = new StackTraceElementProxy(null);
134+
String originalNullAsString = originalNull.getSTEAsString();
135+
136+
StackTraceElementProxy deserializedNull = roundTripSerialize(originalNull);
137+
assertEquals(originalNull, deserializedNull);
138+
assertEquals(StackTraceElementProxy.NA_SUBSTITUTE, deserializedNull.getStackTraceElement());
139+
assertEquals(originalNullAsString, deserializedNull.getSTEAsString());
140+
}
141+
142+
private StackTraceElementProxy roundTripSerialize(StackTraceElementProxy input) throws IOException, ClassNotFoundException {
143+
ByteArrayOutputStream bos = new ByteArrayOutputStream();
144+
try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
145+
oos.writeObject(input);
146+
}
147+
try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()))) {
148+
return (StackTraceElementProxy) ois.readObject();
149+
}
150+
}
151+
}

0 commit comments

Comments
 (0)