Any reason why some of these tests won't work?

access denied ("java.lang.reflect.ReflectPermission" "suppressAccessChecks") (7 occurrences)

symptom: java.security.AccessControlException: access denied ("java.lang.reflect.ReflectPermission" "suppressAccessChecks")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:457)
at java.security.AccessController.checkPermission(AccessController.java:884)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at student.testingsupport.ExitPreventingSecurityManager.checkPermission(ExitPreventingSecurityManager.java:83)

 

import static org.junit.Assert.*;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;

import org.junit.Before;
import org.junit.Test;

public class DeckTest {
  private Deck deck;

  @Before
  public void setUp() throws Exception {
    deck = new Deck();
  }

  @Test
  public void testDeckConstants() {
    assertEquals(Deck.SIZE, 52);
    assertEquals(Deck.SHUFFLE_REPEAT, 3);
  }

  @Test
  public void testConstructor() throws Exception {
    deck = new Deck();
    Class deckClass = deck.getClass();

    // test private cards array
    Field cardsArray = deckClass.getDeclaredField("cards");
    cardsArray.setAccessible(true);
    Card[] cards = (Card[]) cardsArray.get(deck);
    int i = 0;
    for (String suit : Card.SUITS)
      for (String value : Card.VALUES)
        assertEquals(cards[i++], new Card(suit, value));

    // test private nextCardIndex variable should be zero
    Field nextCardIndex = deckClass.getDeclaredField("nextCardIndex");
    nextCardIndex.setAccessible(true);
    assertEquals((Integer) nextCardIndex.get(deck), new Integer(0));
  }

  @Test
  public void testShuffle() {
    // This test is inspired by experiments 1.1.36 and 1.1.37 in Sedgewick
    // and Wayne, Algorithms, 4th edition. It tests whether, over many
    // shuffles, each card is equally likely to end up in each position. It
    // may fail once in a great while, but it generally passes for a correct
    // shuffling algorithm and fails for common incorrect algorithms.
    Deck unshuffled = new Deck();
    int[][] counts = new int[Deck.SIZE][Deck.SIZE];
    for (int trial = 0; trial < 5000; trial++) {
      boolean[] seen = new boolean[Deck.SIZE];
      deck = new Deck();
      deck.shuffle();
      for (int i = 0; i < Deck.SIZE; i++) {
        for (int j = 0; j < Deck.SIZE; j++) {
          Card a = unshuffled.get(i);
          Card b = deck.get(j);
          if (a.equals(b)) {
            counts[i][j]++;
            assertFalse(seen[i]);
            seen[i] = true;
          }
        }
      }
    }
    for (int i = 0; i < Deck.SIZE; i++) {
      for (int j = 0; j < Deck.SIZE; j++) {
        assertTrue(counts[i][j] > (5000 / 52.0) * 0.5);
        assertTrue(counts[i][j] < (5000 / 52.0) * 1.5);
      }
    }
  }

  @Test
  public void testToString() throws Exception {
    Class deckClass = deck.getClass();
    Field cardsArray = deckClass.getDeclaredField("cards");
    cardsArray.setAccessible(true);
    Card[] cards = (Card[]) cardsArray.get(deck);
    String str = "";
    for (int i = 0; i < Deck.SIZE; i++) {
      if (i % 13 == 0) str += "\n";
      str += cards[i] + " ";
    }
    assertEquals(deck.toString(), str);
    deck.shuffle();
    cards = (Card[]) cardsArray.get(deck);
    str = "";
    for (int i = 0; i < Deck.SIZE; i++) {
      if (i % 13 == 0) str += "\n";
      str += cards[i] + " ";
    }
    assertEquals(deck.toString(), str);
  }

  @Test
  public void testDeal() {
    for (String suit : Card.SUITS)
      for (String value : Card.VALUES)
        assertEquals(deck.deal(), new Card(suit, value));
    assertNull(deck.deal());
    deck.shuffle();
    HashSet hash = new HashSet();
    for (int i = 0; i < Deck.SIZE; i++) {
      Card dealt = deck.deal();
      assertNotNull(dealt);
      hash.add(dealt);
    }
    assertNull(deck.deal());
    assertEquals(hash.size(), Deck.SIZE);
  }

  @Test
  public void testDealParameterized() throws Exception {
    Card[] dealt;
    for (int i = 0; i < Deck.SIZE - 2; i++) {
      deck.deal();
    }
    dealt = deck.deal(10);
    assertNull(dealt);
    deck = new Deck();
    dealt = deck.deal(10);
    Class deckClass = deck.getClass();
    Field cardsArray = deckClass.getDeclaredField("cards");
    cardsArray.setAccessible(true);
    Card[] cards = (Card[]) cardsArray.get(deck);
    Card[] cardsFirst10 = new Card[10];
    System.arraycopy(cards, 0, cardsFirst10, 0, 10);
    for (int i = 0; i < 10; i++) {
      assertEquals(cardsFirst10[i], dealt[i]);
    }
  }

  @Test
  public void testBurn() throws Exception {
    Class deckClass = deck.getClass();
    Field nextCardIndex = deckClass.getDeclaredField("nextCardIndex");
    nextCardIndex.setAccessible(true);
    assertEquals((Integer) nextCardIndex.get(deck), new Integer(0));
    deck.burn();
    assertEquals((Integer) nextCardIndex.get(deck), new Integer(1));
    deck.burn();
    deck.burn();
    deck.burn();
    assertEquals((Integer) nextCardIndex.get(deck), new Integer(4));
  }

  @Test
  public void testSwap() throws Exception {
    // test private swap method via reflection
    Class deckClass = deck.getClass();
    Field cardsArray = deckClass.getDeclaredField("cards");
    cardsArray.setAccessible(true);
    Card[] cards = (Card[]) cardsArray.get(deck);
    Card c0 = cards[0];
    Card c1 = cards[1];
    Method method = deckClass.getDeclaredMethod("swap", new Class[] {Integer.TYPE, Integer.TYPE});
    method.setAccessible(true);
    method.invoke(deck, 0, 1);
    assertEquals(c0, cards[1]);
    assertEquals(c1, cards[0]);
    deck.shuffle();
    c0 = cards[0];
    c1 = cards[1];
    method.invoke(deck, 0, 1);
    assertEquals(c0, cards[1]);
    assertEquals(c1, cards[0]);
  }

  @Test
  public void testInBounds() throws Exception {
    Class deckClass = deck.getClass();
    Method method = deckClass.getDeclaredMethod("inBounds", new Class[] {Integer.TYPE});
    method.setAccessible(true);
    assertTrue((Boolean) method.invoke(deck, 0));
    assertTrue((Boolean) method.invoke(deck, 13));
    assertTrue((Boolean) method.invoke(deck, 51));
    assertFalse((Boolean) method.invoke(deck, -1));
    assertFalse((Boolean) method.invoke(deck, 52));
    assertFalse((Boolean) method.invoke(deck, 53));
  }

  @Test
  public void testSort() throws Exception {
    Class deckClass = deck.getClass();
    Field cardsArray = deckClass.getDeclaredField("cards");
    cardsArray.setAccessible(true);
    Card[] cards = (Card[]) cardsArray.get(deck);
    Card[] part1 = {cards[0], cards[1], cards[2]};
    Card[] part2 = {cards[10], cards[11], cards[12]};
    Card[] part3 = {cards[49], cards[50], cards[51]};
    assertArrayEquals(new Card[] {cards[0], cards[1], cards[2]}, part1);
    assertArrayEquals(new Card[] {cards[10], cards[11], cards[12]}, part2);
    assertArrayEquals(new Card[] {cards[49], cards[50], cards[51]}, part3);
    deck.shuffle();
    deck.shuffle();
    deck.sort();
    assertArrayEquals(new Card[] {cards[0], cards[1], cards[2]}, part1);
    assertArrayEquals(new Card[] {cards[10], cards[11], cards[12]}, part2);
    assertArrayEquals(new Card[] {cards[49], cards[50], cards[51]}, part3);
  }
}
Groups:

Comments

Stephen Edwards

The security sandboxing on

The security sandboxing on Web-CAT does not allow student-level code (or code called from student-level code) unrestricted access to all of Java's features.  In particular, no, students cannot suppress visibility access checks via reflection.

For instructor-written tests, we do provide a sandbox-compatible reflection library for accessing/manipulating student code, and there's even a journal article describing the API.  Let me know if you want more information about using that (it is distributed as part of the student.jar library, for instructors to independently run tests using those features).

verdicchio

Definitely

Thanks for the quick reply. I'd definitely like to learn how to adapt my tests so I can test private class members via reflection. In fact, the test code I provided here was my first attempt at reflection, so I'm quite new at it. I'm hoping to adapt these tests ASAP so I can distribute the assignment.

verdicchio

Just found this...

http://web-cat.org/junit-quickstart/index.html

That page explains student.jar and how to get started well. Can you confirm 1) that is the up to date version of student.jar 2) if you have any more examples, especially for doing reflection like I was trying to, and 3) if there are any docs using junit 4 style?

Thanks!

Stephen Edwards

Yes, that is the current

Yes, that is the current version of student.jar--the link there points to the latest download on SourceForge for the file.  The source is on SourceForge as well, should you want to look at it.

For reflection, take a look at this paper: http://benthamopen.com/contents/pdf/TOSEJ/TOSEJ-7-38.pdf

The corresponding class is included in student.jar as student.testingsupport.ReflectionSupport.  By statically importing from this class, you can get access to utility methods for finding classes, calling constructors, invoking methods, and accessing fields.  Appropriate JUnit test failure exceptions with meaningful messages are generated when trying to access features that cannot be resolved.  Method invocation in particular handles autoboxing, implicit type conversions, and overload resolution for you, unlike the standard library API.  All of the methods work well without requiring explicit exception handlers for reflection errors.  Details are in the paper.

If you'd like further examples, post a small, simple test method representing the direct (non-reflective) way you want to do something, and I can show you how it would translate to calls in this library.

Regarding JUnit 4-style tests, the student.jar file now includes a complete JUnit runtime, as well as a custom JUnit runner that provides support for both JUnit 3-style and JUnit 4-style conventions.  You can freely use JUnit 4 annotations in place of JUnit 3 naming conventions where desired.  We still recommend for students to extend student.TestCase (even though JUnit 4 doesn't use a base class), because there are a number of extensions and additional safety mechanisms provided by that base class that prevent or point out common errors by beginners, and also some healthy support for testing I/O through System.in/System.out that is also very useful (for instructors as well as students).

I should probably post a JUnit 4 version of that quickstart guide so people have a choice right up front on the page ... maybe the next time I have a break ;-).