test(05-02): add concurrency-aware assertion removal tests
- 14 new tests in TestConcurrencyPatterns class - synchronized blocks/methods preserved after transformation - volatile field reads, AtomicInteger ops preserved - ConcurrentHashMap, Thread.sleep, wait/notify patterns preserved - ReentrantLock, CountDownLatch patterns preserved - Real-world TokenBucket and CircularBuffer patterns validated - AssertJ assertion on synchronized method call validated - Total: 71 tests (57 existing + 14 new), all passing
This commit is contained in:
parent
e958e4e9f4
commit
8d42ed93dd
1 changed files with 296 additions and 0 deletions
|
|
@ -959,3 +959,299 @@ void testFibonacci() {
|
||||||
}"""
|
}"""
|
||||||
result = transform_java_assertions(source, "fibonacci")
|
result = transform_java_assertions(source, "fibonacci")
|
||||||
assert result == expected
|
assert result == expected
|
||||||
|
|
||||||
|
|
||||||
|
class TestConcurrencyPatterns:
|
||||||
|
"""Tests that assertion removal correctly handles Java concurrency constructs.
|
||||||
|
|
||||||
|
Validates that synchronized blocks, volatile field access, atomic operations,
|
||||||
|
concurrent collections, Thread.sleep, wait/notify, and synchronized method
|
||||||
|
modifiers are all preserved verbatim after assertion transformation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_synchronized_method_assertion_removal(self):
|
||||||
|
"""Assertion inside synchronized block is transformed; synchronized wrapper preserved."""
|
||||||
|
source = """\
|
||||||
|
@Test
|
||||||
|
void testSynchronizedAccess() {
|
||||||
|
synchronized (lock) {
|
||||||
|
assertEquals(42, counter.incrementAndGet());
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
expected = """\
|
||||||
|
@Test
|
||||||
|
void testSynchronizedAccess() {
|
||||||
|
synchronized (lock) {
|
||||||
|
Object _cf_result1 = counter.incrementAndGet();
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
result = transform_java_assertions(source, "incrementAndGet")
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
def test_volatile_field_read_preserved(self):
|
||||||
|
"""Assertion wrapping a volatile field reader is transformed; method call preserved."""
|
||||||
|
source = """\
|
||||||
|
@Test
|
||||||
|
void testVolatileRead() {
|
||||||
|
assertTrue(buffer.isReady());
|
||||||
|
}"""
|
||||||
|
expected = """\
|
||||||
|
@Test
|
||||||
|
void testVolatileRead() {
|
||||||
|
Object _cf_result1 = buffer.isReady();
|
||||||
|
}"""
|
||||||
|
result = transform_java_assertions(source, "isReady")
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
def test_synchronized_block_with_multiple_assertions(self):
|
||||||
|
"""Multiple assertions inside a synchronized block are all transformed."""
|
||||||
|
source = """\
|
||||||
|
@Test
|
||||||
|
void testSynchronizedBlock() {
|
||||||
|
synchronized (cache) {
|
||||||
|
assertEquals(1, cache.size());
|
||||||
|
assertNotNull(cache.get("key"));
|
||||||
|
assertTrue(cache.containsKey("key"));
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
expected = """\
|
||||||
|
@Test
|
||||||
|
void testSynchronizedBlock() {
|
||||||
|
synchronized (cache) {
|
||||||
|
Object _cf_result1 = cache.size();
|
||||||
|
assertNotNull(cache.get("key"));
|
||||||
|
assertTrue(cache.containsKey("key"));
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
result = transform_java_assertions(source, "size")
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
def test_synchronized_block_multiple_assertions_same_target(self):
|
||||||
|
"""Multiple assertions in synchronized block targeting the same function."""
|
||||||
|
source = """\
|
||||||
|
@Test
|
||||||
|
void testSynchronizedBlock() {
|
||||||
|
synchronized (cache) {
|
||||||
|
assertNotNull(cache.get("key1"));
|
||||||
|
assertNotNull(cache.get("key2"));
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
expected = """\
|
||||||
|
@Test
|
||||||
|
void testSynchronizedBlock() {
|
||||||
|
synchronized (cache) {
|
||||||
|
Object _cf_result1 = cache.get("key1");
|
||||||
|
Object _cf_result2 = cache.get("key2");
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
result = transform_java_assertions(source, "get")
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
def test_atomic_operations_preserved(self):
|
||||||
|
"""Atomic operations (incrementAndGet) are preserved as Object capture calls."""
|
||||||
|
source = """\
|
||||||
|
@Test
|
||||||
|
void testAtomicCounter() {
|
||||||
|
assertEquals(1, counter.incrementAndGet());
|
||||||
|
assertEquals(2, counter.incrementAndGet());
|
||||||
|
}"""
|
||||||
|
expected = """\
|
||||||
|
@Test
|
||||||
|
void testAtomicCounter() {
|
||||||
|
Object _cf_result1 = counter.incrementAndGet();
|
||||||
|
Object _cf_result2 = counter.incrementAndGet();
|
||||||
|
}"""
|
||||||
|
result = transform_java_assertions(source, "incrementAndGet")
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
def test_concurrent_collection_assertion(self):
|
||||||
|
"""ConcurrentHashMap putIfAbsent call is preserved in assertion transformation."""
|
||||||
|
source = """\
|
||||||
|
@Test
|
||||||
|
void testConcurrentMap() {
|
||||||
|
assertEquals("value", concurrentMap.putIfAbsent("key", "value"));
|
||||||
|
}"""
|
||||||
|
expected = """\
|
||||||
|
@Test
|
||||||
|
void testConcurrentMap() {
|
||||||
|
Object _cf_result1 = concurrentMap.putIfAbsent("key", "value");
|
||||||
|
}"""
|
||||||
|
result = transform_java_assertions(source, "putIfAbsent")
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
def test_thread_sleep_with_assertion(self):
|
||||||
|
"""Thread.sleep() before assertion is preserved verbatim."""
|
||||||
|
source = """\
|
||||||
|
@Test
|
||||||
|
void testWithThreadSleep() throws InterruptedException {
|
||||||
|
Thread.sleep(100);
|
||||||
|
assertEquals(42, processor.getResult());
|
||||||
|
}"""
|
||||||
|
expected = """\
|
||||||
|
@Test
|
||||||
|
void testWithThreadSleep() throws InterruptedException {
|
||||||
|
Thread.sleep(100);
|
||||||
|
Object _cf_result1 = processor.getResult();
|
||||||
|
}"""
|
||||||
|
result = transform_java_assertions(source, "getResult")
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
def test_synchronized_method_signature_preserved(self):
|
||||||
|
"""synchronized modifier on a test method is preserved after transformation."""
|
||||||
|
source = """\
|
||||||
|
@Test
|
||||||
|
synchronized void testSyncMethod() {
|
||||||
|
assertEquals(10, calculator.compute(5));
|
||||||
|
}"""
|
||||||
|
expected = """\
|
||||||
|
@Test
|
||||||
|
synchronized void testSyncMethod() {
|
||||||
|
Object _cf_result1 = calculator.compute(5);
|
||||||
|
}"""
|
||||||
|
result = transform_java_assertions(source, "compute")
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
def test_wait_notify_pattern_preserved(self):
|
||||||
|
"""wait/notify pattern around an assertion is preserved."""
|
||||||
|
source = """\
|
||||||
|
@Test
|
||||||
|
void testWaitNotify() {
|
||||||
|
synchronized (monitor) {
|
||||||
|
monitor.notify();
|
||||||
|
}
|
||||||
|
assertTrue(listener.wasNotified());
|
||||||
|
}"""
|
||||||
|
expected = """\
|
||||||
|
@Test
|
||||||
|
void testWaitNotify() {
|
||||||
|
synchronized (monitor) {
|
||||||
|
monitor.notify();
|
||||||
|
}
|
||||||
|
Object _cf_result1 = listener.wasNotified();
|
||||||
|
}"""
|
||||||
|
result = transform_java_assertions(source, "wasNotified")
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
def test_reentrant_lock_pattern_preserved(self):
|
||||||
|
"""ReentrantLock acquire/release around assertion is preserved."""
|
||||||
|
source = """\
|
||||||
|
@Test
|
||||||
|
void testReentrantLock() {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
assertEquals(99, sharedResource.getValue());
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
expected = """\
|
||||||
|
@Test
|
||||||
|
void testReentrantLock() {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
Object _cf_result1 = sharedResource.getValue();
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
result = transform_java_assertions(source, "getValue")
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
def test_count_down_latch_pattern_preserved(self):
|
||||||
|
"""CountDownLatch await/countDown around assertion is preserved."""
|
||||||
|
source = """\
|
||||||
|
@Test
|
||||||
|
void testCountDownLatch() throws InterruptedException {
|
||||||
|
latch.countDown();
|
||||||
|
latch.await();
|
||||||
|
assertEquals(42, collector.getTotal());
|
||||||
|
}"""
|
||||||
|
expected = """\
|
||||||
|
@Test
|
||||||
|
void testCountDownLatch() throws InterruptedException {
|
||||||
|
latch.countDown();
|
||||||
|
latch.await();
|
||||||
|
Object _cf_result1 = collector.getTotal();
|
||||||
|
}"""
|
||||||
|
result = transform_java_assertions(source, "getTotal")
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
def test_token_bucket_synchronized_method(self):
|
||||||
|
"""Real pattern: synchronized method call (like TokenBucket.allowRequest) inside assertion."""
|
||||||
|
source = """\
|
||||||
|
@Test
|
||||||
|
void testTokenBucketAllowRequest() {
|
||||||
|
TokenBucket bucket = new TokenBucket(10, 1);
|
||||||
|
assertTrue(bucket.allowRequest());
|
||||||
|
assertTrue(bucket.allowRequest());
|
||||||
|
}"""
|
||||||
|
expected = """\
|
||||||
|
@Test
|
||||||
|
void testTokenBucketAllowRequest() {
|
||||||
|
TokenBucket bucket = new TokenBucket(10, 1);
|
||||||
|
Object _cf_result1 = bucket.allowRequest();
|
||||||
|
Object _cf_result2 = bucket.allowRequest();
|
||||||
|
}"""
|
||||||
|
result = transform_java_assertions(source, "allowRequest")
|
||||||
|
assert result == expected
|
||||||
|
|
||||||
|
def test_circular_buffer_atomic_integer_pattern(self):
|
||||||
|
"""Real pattern: CircularBuffer with AtomicInteger-backed isEmpty/isFull assertions."""
|
||||||
|
source = """\
|
||||||
|
@Test
|
||||||
|
void testCircularBufferOperations() {
|
||||||
|
CircularBuffer<Integer> buffer = new CircularBuffer<>(3);
|
||||||
|
assertTrue(buffer.isEmpty());
|
||||||
|
buffer.put(1);
|
||||||
|
assertFalse(buffer.isEmpty());
|
||||||
|
assertTrue(buffer.put(2));
|
||||||
|
}"""
|
||||||
|
expected = """\
|
||||||
|
@Test
|
||||||
|
void testCircularBufferOperations() {
|
||||||
|
CircularBuffer<Integer> buffer = new CircularBuffer<>(3);
|
||||||
|
Object _cf_result1 = buffer.isEmpty();
|
||||||
|
buffer.put(1);
|
||||||
|
Object _cf_result2 = buffer.isEmpty();
|
||||||
|
Object _cf_result3 = buffer.put(2);
|
||||||
|
}"""
|
||||||
|
result = transform_java_assertions(source, "isEmpty")
|
||||||
|
# isEmpty is target for assertTrue/assertFalse; but put is NOT the target
|
||||||
|
# so only isEmpty calls inside assertions are transformed
|
||||||
|
# Actually: assertTrue(buffer.put(2)) also contains a non-target call
|
||||||
|
# Let's verify what actually happens
|
||||||
|
# put is not "isEmpty", so assertTrue(buffer.put(2)) has no target call -> untouched
|
||||||
|
expected_corrected = """\
|
||||||
|
@Test
|
||||||
|
void testCircularBufferOperations() {
|
||||||
|
CircularBuffer<Integer> buffer = new CircularBuffer<>(3);
|
||||||
|
Object _cf_result1 = buffer.isEmpty();
|
||||||
|
buffer.put(1);
|
||||||
|
Object _cf_result2 = buffer.isEmpty();
|
||||||
|
assertTrue(buffer.put(2));
|
||||||
|
}"""
|
||||||
|
result = transform_java_assertions(source, "isEmpty")
|
||||||
|
assert result == expected_corrected
|
||||||
|
|
||||||
|
def test_concurrent_assertion_with_assertj(self):
|
||||||
|
"""AssertJ assertion on a synchronized method call is correctly transformed."""
|
||||||
|
source = """\
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSynchronizedMethodWithAssertJ() {
|
||||||
|
synchronized (lock) {
|
||||||
|
assertThat(counter.incrementAndGet()).isEqualTo(1);
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
expected = """\
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSynchronizedMethodWithAssertJ() {
|
||||||
|
synchronized (lock) {
|
||||||
|
Object _cf_result1 = counter.incrementAndGet();
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
result = transform_java_assertions(source, "incrementAndGet")
|
||||||
|
assert result == expected
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue