All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.java.html.js.tests.GCBodyTest Maven / Gradle / Ivy

Go to download

Test Compatibility Kit for anyone who wants to consume the net.java.html.json APIs and render their objects using own technology (e.g. own browser, MVVC, etc.).

The newest version!
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package net.java.html.js.tests;

import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import org.netbeans.html.json.tck.KOTest;
import static net.java.html.js.tests.JavaScriptBodyTest.*;

/**
 *
 * @author Jaroslav Tulach
 */
public class GCBodyTest {
    Reference ref;
    int[] arr;
    
    @KOTest public void callbackInterfaceCanDisappear() throws InterruptedException {
        if (ref != null) {
            assertGC(ref, "Can disappear!");
            return;
        }
        Sum s = new Sum();
        int res = Bodies.sumIndirect(s, 22, 20);
        assertEquals(res, 42, "Expecting 42");
        Reference ref = new WeakReference(s);
        s = null;
        assertGC(ref, "Can disappear!");
    }

    @KOTest public void callbackInterfaceShallNotDisappear() throws InterruptedException {
        Sum sum = new Sum();
        Object jsSum = Bodies.sumDelayed(sum);
        Reference ref = new WeakReference(sum);
        sum = null;
        IllegalStateException gcError = null;
        try {
            assertNotGC(ref, false, "object s should still stay");
        } catch (IllegalStateException ex) {
            gcError = ex;
        }

        int res = Bodies.sumNow(jsSum, 22, 20);
        assertEquals(res, 42, "Expecting 42");
        if (gcError != null) {
            throw gcError;
        }
    }
    
    private Object assignInst() {
        Object obj = Bodies.instance(0);
        Object s = new EmptyInstance();
        Bodies.setX(obj, s);
        assertEquals(s, Bodies.readX(obj));
        ref = new WeakReference(s);
        return obj;
}
    
    @KOTest public void holdObjectAndReleaseObject() throws InterruptedException {
        if (ref != null) {
            assertGC(ref, "Can disappear!");
            return;
        }
        
        Object obj = assignInst();
        assertNotNull(ref, "Reference assigned");
        
        assertGC(ref, "Can disappear as it is keepAlive false!");
        assertNotNull(obj, "Object is still present");
    }

    @KOTest public void strongReceiverBehavior() {
        Object v = new EmptyInstance();
        Receiver r = new Receiver(v);
        r.apply();
        assertEquals(v, r.value, "Value is as expected");
    }
    
    @KOTest public void gcReceiverBehavior() throws InterruptedException {
        Receiver r = new Receiver(new EmptyInstance());
        assertGC(r.ref, "The empty instance can be GCed even when referenced from JS");
        r.apply();
        assertEquals(r.value, null, "Setter called with null value");
    }

    @KOTest public void thisIsHeldStrongly() throws Exception {
        Sum s = new Sum();
        Object res = s.jsSum(12, 30);
        int intRes = Bodies.readIntX(res);
        assertEquals(42, intRes);
        WeakReference ref = new WeakReference(s);
        s = null;
        assertNotGC(ref, true, "s cannot disappear: we have reference to s via res.y field");
    }

    @KOTest public void argsArentHeldStrongly() throws Exception {
        Sum s = new Sum();
        Object res = Sum.jsStaticSum(s, 12, 30);
        int intRes = Bodies.readIntX(res);
        assertEquals(42, intRes);
        WeakReference ref = new WeakReference(s);
        s = null;
        assertGC(ref, "Reference to s via res.y field is weak");
    }

    private static Reference sendRunnable(final int[] arr) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                arr[0]++;
            }
        };
        Bodies.asyncCallback(r);
        return new WeakReference(r);
    }
    
    private static class EmptyInstance {
    }
    
    @KOTest public void parametersNeedToRemainInAsyncMode() throws InterruptedException {
        if (ref != null) {
            if (arr[0] != 1) {
                throw new InterruptedException();
            }
            assertGC(ref, "Now the runnable can disappear");
            return;
        }
        arr = new int[] { 0 };
        ref = sendRunnable(arr);
        if (arr[0] == 1) {
            return;
        }
        assertNotGC(ref, false, "The runnable should not be GCed");
        throw new InterruptedException();
    }
    
    private static void assertGC(Reference ref, String msg) throws InterruptedException {
        for (int i = 0; i < 30; i++) {
            if (isGone(ref)) return;
            long then = System.currentTimeMillis();
            int size = Bodies.gc(1 << i);
            long took = System.currentTimeMillis() - then;
            if (took > 3000) {
                throw new InterruptedException(msg + " - giving up after " + took + " ms at size of " + size);
            }
            
            try {
                System.gc();
                System.runFinalization();
            } catch (Error err) {
                err.printStackTrace();
            }
        }
        throw new InterruptedException(msg);
    }

    private static boolean isGone(Reference ref) {
        return ref.get() == null;
    }
    
    private static void assertNotGC(Reference ref, boolean clearJS, String msg) throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            if (ref.get() == null) {
                throw new IllegalStateException(msg);
            }
            if (clearJS) {
                Bodies.gc(Math.pow(2.0, i));
            }
            try {
                System.gc();
                System.runFinalization();
            } catch (Error err) {
                err.printStackTrace();
            }
        }
    }
}