From 616f566cfe60638eb97823e1f63cf203161502da Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Wed, 24 Sep 2014 01:08:38 +0200 Subject: Fix jardiff's Tools.isAccessChange(..): Differentiate between Class, Field and Method and apply all rules of the Java Language Specification Class, Field and Methods have different binary backward compatibility rules as specified in the Java Language Specification, Java SE 7 Edition: - http://docs.oracle.com/javase/specs/jls/se7/html/jls-13.html For Field 'volatile' the Java Language Specification, first edition has been used: - http://www.wsu.edu/UNIX_Systems/java/langspec-1.0/13.doc.html#45194 For each type separate method have been created, i.e. Tools.isAccessChange(). Each new method has the rules referenced and partially copied into the method for better documentation. The now deprecated method Tools.isAccessChange(..) calls Tools.isClassAccessChange(..) and shall be removed. Unit test ToolsTest has been expanded for each type and its rules. --- .../test/java/org/osjava/jardiff/ToolsTest.java | 120 ++++++++++++++++++--- 1 file changed, 105 insertions(+), 15 deletions(-) (limited to 'api/src/test/java/org') diff --git a/api/src/test/java/org/osjava/jardiff/ToolsTest.java b/api/src/test/java/org/osjava/jardiff/ToolsTest.java index 148543a..39683bd 100644 --- a/api/src/test/java/org/osjava/jardiff/ToolsTest.java +++ b/api/src/test/java/org/osjava/jardiff/ToolsTest.java @@ -22,26 +22,116 @@ import static org.junit.Assert.*; public class ToolsTest { + static class lala { + int lala; + } + @Test - public void isAccessChange() { - // A class or method or field can't become final. - assertTrue(Tools.isAccessChange(0, Opcodes.ACC_FINAL)); - assertTrue(Tools.isAccessChange(0, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL)); + public void isClassAccessChange() { + // A class can't become final. + assertTrue(Tools.isClassAccessChange(0, Opcodes.ACC_FINAL)); + assertTrue(Tools.isClassAccessChange(0, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL)); // ... but can become non-final. - assertFalse(Tools.isAccessChange(Opcodes.ACC_FINAL, 0)); - assertFalse(Tools.isAccessChange(Opcodes.ACC_FINAL + Opcodes.ACC_PUBLIC, Opcodes.ACC_PUBLIC)); + assertFalse(Tools.isClassAccessChange(Opcodes.ACC_FINAL, 0)); + assertFalse(Tools.isClassAccessChange(Opcodes.ACC_FINAL + Opcodes.ACC_PUBLIC, Opcodes.ACC_PUBLIC)); + // No matter the final access, can't become protected or private or // package if it was public. - assertTrue(Tools.isAccessChange(Opcodes.ACC_FINAL + Opcodes.ACC_PUBLIC, 0)); - assertTrue(Tools.isAccessChange(Opcodes.ACC_PUBLIC, Opcodes.ACC_PROTECTED)); - // A class or method can become concrete. - assertFalse(Tools.isAccessChange(Opcodes.ACC_ABSTRACT, 0)); - assertFalse(Tools.isAccessChange(Opcodes.ACC_ABSTRACT + Opcodes.ACC_PUBLIC, Opcodes.ACC_PUBLIC)); - assertFalse(Tools.isAccessChange(Opcodes.ACC_ABSTRACT + Opcodes.ACC_PROTECTED, Opcodes.ACC_PROTECTED)); + assertTrue(Tools.isClassAccessChange(Opcodes.ACC_FINAL + Opcodes.ACC_PUBLIC, 0)); + assertTrue(Tools.isClassAccessChange(Opcodes.ACC_PUBLIC, Opcodes.ACC_PROTECTED)); + // A class can become concrete. + assertFalse(Tools.isClassAccessChange(Opcodes.ACC_ABSTRACT, 0)); + assertFalse(Tools.isClassAccessChange(Opcodes.ACC_ABSTRACT + Opcodes.ACC_PUBLIC, Opcodes.ACC_PUBLIC)); + assertFalse(Tools.isClassAccessChange(Opcodes.ACC_ABSTRACT + Opcodes.ACC_PROTECTED, Opcodes.ACC_PROTECTED)); // ...but can't become abstract - assertTrue(Tools.isAccessChange(0, Opcodes.ACC_ABSTRACT)); - assertTrue(Tools.isAccessChange(Opcodes.ACC_PUBLIC, Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT)); - assertTrue(Tools.isAccessChange(Opcodes.ACC_PROTECTED, Opcodes.ACC_PROTECTED + Opcodes.ACC_ABSTRACT)); + assertTrue(Tools.isClassAccessChange(0, Opcodes.ACC_ABSTRACT)); + assertTrue(Tools.isClassAccessChange(Opcodes.ACC_PUBLIC, Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT)); + assertTrue(Tools.isClassAccessChange(Opcodes.ACC_PROTECTED, Opcodes.ACC_PROTECTED + Opcodes.ACC_ABSTRACT)); } + @Test + public void isFieldAccessChange() { + // A field can't become final. + assertTrue(Tools.isFieldAccessChange(0, Opcodes.ACC_FINAL)); + assertTrue(Tools.isFieldAccessChange(0, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL)); + // ... but can become non-final. + assertFalse(Tools.isFieldAccessChange(Opcodes.ACC_FINAL, 0)); + assertFalse(Tools.isFieldAccessChange(Opcodes.ACC_FINAL + Opcodes.ACC_PUBLIC, Opcodes.ACC_PUBLIC)); + + // No matter the final access, can't become protected or private or + // package if it was public. + assertTrue(Tools.isFieldAccessChange(Opcodes.ACC_FINAL + Opcodes.ACC_PUBLIC, 0)); + assertTrue(Tools.isFieldAccessChange(Opcodes.ACC_PUBLIC, Opcodes.ACC_PROTECTED)); + + // A field can't change static + assertTrue(Tools.isFieldAccessChange(Opcodes.ACC_STATIC, 0)); + assertTrue(Tools.isFieldAccessChange(Opcodes.ACC_STATIC + Opcodes.ACC_PUBLIC, Opcodes.ACC_PUBLIC)); + + // A field can't change volatile + assertTrue(Tools.isFieldAccessChange(Opcodes.ACC_VOLATILE, 0)); + assertTrue(Tools.isFieldAccessChange(Opcodes.ACC_VOLATILE + Opcodes.ACC_PUBLIC, Opcodes.ACC_PUBLIC)); + + // A field can change transient + assertFalse(Tools.isFieldAccessChange(0, + Opcodes.ACC_TRANSIENT)); + assertFalse(Tools.isFieldAccessChange(Opcodes.ACC_PUBLIC, + Opcodes.ACC_PUBLIC + Opcodes.ACC_TRANSIENT)); + assertFalse(Tools.isFieldAccessChange(Opcodes.ACC_TRANSIENT, + 0)); + assertFalse(Tools.isFieldAccessChange(Opcodes.ACC_PUBLIC + Opcodes.ACC_TRANSIENT, + Opcodes.ACC_PUBLIC)); + } + + @Test + public void isMethodAccessChange() { + // A non-static method can't become final. + assertTrue(Tools.isMethodAccessChange(0, Opcodes.ACC_FINAL)); + assertTrue(Tools.isMethodAccessChange(0, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL)); + // ... but can become non-final. + assertFalse(Tools.isMethodAccessChange(Opcodes.ACC_FINAL, 0)); + assertFalse(Tools.isMethodAccessChange(Opcodes.ACC_FINAL + Opcodes.ACC_PUBLIC, Opcodes.ACC_PUBLIC)); + // ... but a static method can become final! + assertFalse(Tools.isMethodAccessChange(Opcodes.ACC_STATIC, + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL)); + assertFalse(Tools.isMethodAccessChange(Opcodes.ACC_STATIC + Opcodes.ACC_PUBLIC, + Opcodes.ACC_STATIC + Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL)); + + // No matter the final access, can't become protected or private or + // package if it was public. + assertTrue(Tools.isMethodAccessChange(Opcodes.ACC_FINAL + Opcodes.ACC_PUBLIC, 0)); + assertTrue(Tools.isMethodAccessChange(Opcodes.ACC_PUBLIC, Opcodes.ACC_PROTECTED)); + // A class or method can become concrete. + assertFalse(Tools.isMethodAccessChange(Opcodes.ACC_ABSTRACT, 0)); + assertFalse(Tools.isMethodAccessChange(Opcodes.ACC_ABSTRACT + Opcodes.ACC_PUBLIC, Opcodes.ACC_PUBLIC)); + assertFalse(Tools.isMethodAccessChange(Opcodes.ACC_ABSTRACT + Opcodes.ACC_PROTECTED, Opcodes.ACC_PROTECTED)); + // ...but can't become abstract + assertTrue(Tools.isMethodAccessChange(0, Opcodes.ACC_ABSTRACT)); + assertTrue(Tools.isMethodAccessChange(Opcodes.ACC_PUBLIC, Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT)); + assertTrue(Tools.isMethodAccessChange(Opcodes.ACC_PROTECTED, Opcodes.ACC_PROTECTED + Opcodes.ACC_ABSTRACT)); + + // A method can't change static + assertTrue(Tools.isMethodAccessChange(Opcodes.ACC_STATIC, 0)); + assertTrue(Tools.isMethodAccessChange(Opcodes.ACC_STATIC + Opcodes.ACC_PUBLIC, Opcodes.ACC_PUBLIC)); + + // A method can change synchronized + assertFalse(Tools.isMethodAccessChange(0, + Opcodes.ACC_SYNCHRONIZED)); + assertFalse(Tools.isMethodAccessChange(Opcodes.ACC_PUBLIC, + Opcodes.ACC_PUBLIC + Opcodes.ACC_SYNCHRONIZED)); + assertFalse(Tools.isMethodAccessChange(Opcodes.ACC_SYNCHRONIZED, + 0)); + assertFalse(Tools.isMethodAccessChange(Opcodes.ACC_PUBLIC + Opcodes.ACC_SYNCHRONIZED, + Opcodes.ACC_PUBLIC)); + + // A method can change native + assertFalse(Tools.isMethodAccessChange(0, + Opcodes.ACC_NATIVE)); + assertFalse(Tools.isMethodAccessChange(Opcodes.ACC_PUBLIC, + Opcodes.ACC_PUBLIC + Opcodes.ACC_NATIVE)); + assertFalse(Tools.isMethodAccessChange(Opcodes.ACC_NATIVE, + 0)); + assertFalse(Tools.isMethodAccessChange(Opcodes.ACC_PUBLIC + Opcodes.ACC_NATIVE, + Opcodes.ACC_PUBLIC)); + } + } -- cgit v1.2.3