changeset 942:7e5cbd159365

Enable some @Ignored help tests Reviewed-by: jerboaa, neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-January/005393.html
author Omair Majid <omajid@redhat.com>
date Tue, 29 Jan 2013 10:24:50 -0500
parents bb6bd5efc633
children 4c4b627b3f9c
files distribution/src/test/java/com/redhat/thermostat/distribution/CliTest.java launcher/src/main/java/com/redhat/thermostat/launcher/internal/Activator.java launcher/src/main/java/com/redhat/thermostat/launcher/internal/HelpCommand.java launcher/src/main/java/com/redhat/thermostat/launcher/internal/LocaleResources.java launcher/src/main/resources/META-INF/services/com.redhat.thermostat.common.cli.Command launcher/src/main/resources/com/redhat/thermostat/launcher/internal/strings.properties launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/HelpCommandTest.java launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java
diffstat 9 files changed, 117 insertions(+), 128 deletions(-) [+]
line wrap: on
line diff
--- a/distribution/src/test/java/com/redhat/thermostat/distribution/CliTest.java	Tue Jan 29 14:47:23 2013 +0100
+++ b/distribution/src/test/java/com/redhat/thermostat/distribution/CliTest.java	Tue Jan 29 10:24:50 2013 -0500
@@ -91,7 +91,6 @@
         assertEquals(stdErr, "");
     }
 
-    @Ignore("this is currently broken; help's usage includes stuff about usernames and passwords")
     @Test
     public void testHelpOnHelp() throws Exception {
         Spawn shell = spawnThermostat("help", "help");
@@ -102,7 +101,7 @@
 
         String[] lines = stdOut.split("\n");
         String usage = lines[0];
-        assertEquals("usage: help [command-name]", usage);
+        assertEquals("usage: thermostat help [command-name]", usage);
 
         assertEquals(stdErr, "");
     }
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/Activator.java	Tue Jan 29 14:47:23 2013 +0100
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/Activator.java	Tue Jan 29 10:24:50 2013 -0500
@@ -38,21 +38,23 @@
 
 import java.io.File;
 
+import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.util.tracker.ServiceTracker;
 import org.osgi.util.tracker.ServiceTrackerCustomizer;
 
-import com.redhat.thermostat.common.CommandLoadingBundleActivator;
 import com.redhat.thermostat.common.Launcher;
 import com.redhat.thermostat.common.cli.CommandContextFactory;
 import com.redhat.thermostat.common.cli.CommandInfoSource;
+import com.redhat.thermostat.common.cli.CommandRegistry;
+import com.redhat.thermostat.common.cli.CommandRegistryImpl;
 import com.redhat.thermostat.common.config.Configuration;
 import com.redhat.thermostat.launcher.BundleManager;
 import com.redhat.thermostat.utils.keyring.Keyring;
 
-public class Activator extends CommandLoadingBundleActivator {
+public class Activator implements BundleActivator {
     
     @SuppressWarnings({"rawtypes", "unchecked"})
     class RegisterLauncherCustomizer implements ServiceTrackerCustomizer {
@@ -111,23 +113,48 @@
     @SuppressWarnings("rawtypes")
     private ServiceTracker serviceTracker;
 
+    private CommandRegistry registry;
+
+    private ServiceTracker commandInfoSourceTracker;
+
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @Override
     public void start(final BundleContext context) throws Exception {
-        super.start(context);
         BundleManager bundleService = new BundleManagerImpl(new Configuration());
         ServiceTrackerCustomizer customizer = new RegisterLauncherCustomizer(context, bundleService);
         serviceTracker = new ServiceTracker(context, Keyring.class, customizer);
         // Track for Keyring service.
         serviceTracker.open();
+
+        final HelpCommand helpCommand = new HelpCommand();
+
+        commandInfoSourceTracker = new ServiceTracker(context, CommandInfoSource.class, null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                CommandInfoSource infoSource = (CommandInfoSource) super.addingService(reference);
+                helpCommand.setCommandInfoSource(infoSource);
+                return infoSource;
+            }
+
+            @Override
+            public void removedService(ServiceReference reference, Object service) {
+                helpCommand.setCommandInfoSource(null);
+                super.removedService(reference, service);
+            }
+        };
+        commandInfoSourceTracker.open();
+
+        registry = new CommandRegistryImpl(context);
+        registry.registerCommand(helpCommand);
     }
 
     @Override
     public void stop(BundleContext context) throws Exception {
-        super.stop(context);
         if (serviceTracker != null) {
             serviceTracker.close();
         }
+        commandInfoSourceTracker.close();
+        registry.unregisterCommands();
     }
 }
 
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/HelpCommand.java	Tue Jan 29 14:47:23 2013 +0100
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/HelpCommand.java	Tue Jan 29 10:24:50 2013 -0500
@@ -45,9 +45,6 @@
 
 import org.apache.commons.cli.HelpFormatter;
 import org.apache.commons.cli.Options;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
 
 import com.redhat.thermostat.common.cli.Arguments;
 import com.redhat.thermostat.common.cli.CommandContext;
@@ -68,10 +65,22 @@
 
     private static final CommandInfoComparator comparator = new CommandInfoComparator();
 
+    private CommandInfoSource commandInfoSource;
+
+    public void setCommandInfoSource(CommandInfoSource source) {
+        this.commandInfoSource = source;
+    }
+
     @Override
     public void run(CommandContext ctx) {
         Arguments args = ctx.getArguments();
         List<String> nonParsed = args.getNonOptionArguments();
+
+        if (commandInfoSource == null) {
+            ctx.getConsole().getError().print(translator.localize(LocaleResources.CANNOT_GET_COMMAND_INFO));
+            return;
+        }
+
         if (nonParsed.isEmpty()) {
             printCommandSummaries(ctx);
         } else {
@@ -80,15 +89,11 @@
     }
 
     private void printCommandSummaries(CommandContext ctx) {
-        BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
-        ServiceReference infosRef = context.getServiceReference(CommandInfoSource.class);
-        CommandInfoSource infos = (CommandInfoSource) context.getService(infosRef);
         ctx.getConsole().getOutput().print(translator.localize(LocaleResources.COMMAND_HELP_COMMAND_LIST_HEADER));
 
         TableRenderer renderer = new TableRenderer(2, COMMANDS_COLUMNS_WIDTH);
 
-        Collection<CommandInfo> commandInfos = infos.getCommandInfos();
-        context.ungetService(infosRef);
+        Collection<CommandInfo> commandInfos = commandInfoSource.getCommandInfos();
         List<CommandInfo> sortedCommandInfos = new ArrayList<>(commandInfos);
 
         Collections.sort(sortedCommandInfos, comparator);
@@ -103,17 +108,12 @@
     }
 
     private void printCommandUsage(CommandContext ctx, String cmdName) {
-        BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
-        ServiceReference infosRef = context.getServiceReference(CommandInfoSource.class);
-        CommandInfoSource infos = (CommandInfoSource) context.getService(infosRef);
         try {
-            CommandInfo info = infos.getCommandInfo(cmdName);
+            CommandInfo info = commandInfoSource.getCommandInfo(cmdName);
             printHelp(ctx, info);
         } catch (CommandInfoNotFoundException notFound) {
             ctx.getConsole().getOutput().print(translator.localize(LocaleResources.UNKNOWN_COMMAND, cmdName));
             printCommandSummaries(ctx);
-        } finally {
-            context.ungetService(infosRef);
         }
     }
 
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LocaleResources.java	Tue Jan 29 14:47:23 2013 +0100
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LocaleResources.java	Tue Jan 29 10:24:50 2013 -0500
@@ -40,7 +40,9 @@
 
 public enum LocaleResources {
 
+    CANNOT_GET_COMMAND_INFO,
     UNKNOWN_COMMAND,
+
     COMMAND_HELP_COMMAND_LIST_HEADER,
     OPTION_DB_URL_DESC,
     OPTION_USERNAME_DESC,
--- a/launcher/src/main/resources/META-INF/services/com.redhat.thermostat.common.cli.Command	Tue Jan 29 14:47:23 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-com.redhat.thermostat.launcher.internal.HelpCommand
--- a/launcher/src/main/resources/com/redhat/thermostat/launcher/internal/strings.properties	Tue Jan 29 14:47:23 2013 +0100
+++ b/launcher/src/main/resources/com/redhat/thermostat/launcher/internal/strings.properties	Tue Jan 29 10:24:50 2013 -0500
@@ -1,3 +1,4 @@
+CANNOT_GET_COMMAND_INFO = no information about commands
 UNKNOWN_COMMAND = unknown command ''{0}''\n
 
 COMMAND_HELP_COMMAND_LIST_HEADER = list of commands:\n\n
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java	Tue Jan 29 14:47:23 2013 +0100
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java	Tue Jan 29 10:24:50 2013 -0500
@@ -64,6 +64,7 @@
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.framework.launch.Framework;
@@ -229,8 +230,9 @@
         return tempDir;
     }
 
-    private void setupOsgiRegistryImplMock() {
+    private void setupOsgiRegistryImplMock() throws InvalidSyntaxException {
         PowerMockito.mockStatic(FrameworkUtil.class);
+        when(FrameworkUtil.createFilter(anyString())).thenCallRealMethod();
         Bundle mockBundle = mock(Bundle.class);
         when(FrameworkUtil.getBundle(BundleManagerImpl.class)).thenReturn(mockBundle);
         when(mockBundle.getBundleContext()).thenReturn(context);
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/HelpCommandTest.java	Tue Jan 29 14:47:23 2013 +0100
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/HelpCommandTest.java	Tue Jan 29 10:24:50 2013 -0500
@@ -37,8 +37,9 @@
 package com.redhat.thermostat.launcher.internal;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.isA;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -46,67 +47,71 @@
 import java.util.Arrays;
 import java.util.Collection;
 
-import org.junit.After;
+import org.apache.commons.cli.Options;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
 
 import com.redhat.thermostat.common.cli.Arguments;
 import com.redhat.thermostat.common.cli.CommandInfo;
 import com.redhat.thermostat.common.cli.CommandInfoNotFoundException;
 import com.redhat.thermostat.common.cli.CommandInfoSource;
 import com.redhat.thermostat.common.cli.SimpleArguments;
-import com.redhat.thermostat.launcher.TestCommand;
-import com.redhat.thermostat.launcher.internal.HelpCommand;
 import com.redhat.thermostat.test.TestCommandContextFactory;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({HelpCommand.class, FrameworkUtil.class})
 public class HelpCommandTest {
 
     private TestCommandContextFactory  ctxFactory;
-
-    private void mockCommandInfoSourceService(CommandInfoSource infos) {
-        PowerMockito.mockStatic(FrameworkUtil.class);
-        Bundle bundle = mock(Bundle.class);
-        BundleContext bCtx = mock(BundleContext.class);
-        when(bundle.getBundleContext()).thenReturn(bCtx);
-        ServiceReference infosRef = mock(ServiceReference.class);
-        when(bCtx.getServiceReference(CommandInfoSource.class)).thenReturn(infosRef);
-        when(bCtx.getService(infosRef)).thenReturn(infos);
-        when(FrameworkUtil.getBundle(isA(HelpCommand.class.getClass()))).thenReturn(bundle);
-    }
+    private CommandInfoSource infos;
 
     @Before
     public void setUp() {
         ctxFactory = new TestCommandContextFactory();
-    }
 
-    @After
-    public void tearDown() {
-        ctxFactory = null;
+        infos = mock(CommandInfoSource.class);
     }
 
     @Test
-    public void testName() {
+    public void verifyName() {
         HelpCommand cmd = new HelpCommand();
         assertEquals("help", cmd.getName());
     }
 
     @Test
+    public void verifyDescAndUsage() {
+        HelpCommand cmd = new HelpCommand();
+        assertNotNull(cmd.getDescription());
+        assertNotNull(cmd.getUsage());
+    }
+
+    @Test
+    public void verifyCommandIsAvailableEverywhere() {
+        HelpCommand cmd = new HelpCommand();
+        assertTrue(cmd.isAvailableInShell());
+        assertTrue(cmd.isAvailableOutsideShell());
+    }
+
+    @Test
+    public void verifyStorageIsNotRequired() {
+        HelpCommand cmd = new HelpCommand();
+        assertFalse(cmd.isStorageRequired());
+    }
+
+    @Test
+    public void verifyHelpFailsWithoutCommandInfoSource() {
+        HelpCommand cmd = new HelpCommand();
+
+        Arguments args = mock(Arguments.class);
+        when(args.getNonOptionArguments()).thenReturn(Arrays.asList("test1"));
+        cmd.run(ctxFactory.createContext(args));
+
+        assertEquals("no information about commands", ctxFactory.getError());
+        assertEquals("", ctxFactory.getOutput());
+    }
+
+    @Test
     public void verifyHelpNoArgPrintsListOfCommandsNoCommands() {
-        CommandInfoSource infos = mock(CommandInfoSource.class);
-        mockCommandInfoSourceService(infos);
-
         HelpCommand cmd = new HelpCommand();
+        cmd.setCommandInfoSource(infos);
         Arguments args = mock(Arguments.class);
         cmd.run(ctxFactory.createContext(args));
         String expected = "list of commands:\n\n";
@@ -116,8 +121,6 @@
 
     @Test
     public void verifyHelpNoArgPrintsListOfCommands2Commands() {
-
-        CommandInfoSource infos = mock(CommandInfoSource.class);
         Collection<CommandInfo> infoList = new ArrayList<CommandInfo>();
         
         CommandInfo info1 = mock(CommandInfo.class);
@@ -131,9 +134,10 @@
         infoList.add(info2);
 
         when(infos.getCommandInfos()).thenReturn(infoList);
-        mockCommandInfoSourceService(infos);
 
         HelpCommand cmd = new HelpCommand();
+        cmd.setCommandInfoSource(infos);
+
         Arguments args = mock(Arguments.class);
         cmd.run(ctxFactory.createContext(args));
         String expected = "list of commands:\n\n"
@@ -143,70 +147,61 @@
         assertEquals(expected, actual);
     }
 
-    // TODO bug wrt CommonCommandOptions makes this test fail.  Commenting out until that is resolved
-    @Ignore
     @Test
     public void verifyHelpKnownCmdPrintsCommandUsage() {
-        CommandInfoSource infos = mock(CommandInfoSource.class);
-        Collection<CommandInfo> infoList = new ArrayList<CommandInfo>();
-        
-        CommandInfo info1 = mock(CommandInfo.class);
-        when(info1.getName()).thenReturn("test1");
-        when(info1.getDescription()).thenReturn("test command 1");
-        infoList.add(info1);
+        CommandInfo testCommandInfo = mock(CommandInfo.class);
+        when(testCommandInfo.getName()).thenReturn("test1");
+        when(testCommandInfo.getUsage()).thenReturn("usage of test command");
+        when(testCommandInfo.getDescription()).thenReturn("description of test command");
+        when(testCommandInfo.getOptions()).thenReturn(new Options());
 
-        when(infos.getCommandInfos()).thenReturn(infoList);
-        mockCommandInfoSourceService(infos);
+        when(infos.getCommandInfo("test1")).thenReturn(testCommandInfo);
 
         HelpCommand cmd = new HelpCommand();
+        cmd.setCommandInfoSource(infos);
         Arguments args = mock(Arguments.class);
         when(args.getNonOptionArguments()).thenReturn(Arrays.asList("test1"));
         cmd.run(ctxFactory.createContext(args));
 
         String actual = ctxFactory.getOutput();
-        assertEquals("usage: test1 [--logLevel <arg>] [--password <arg>] [--username <arg>]\n" +
-                     "test usage command 1\n" +
-                     "     --logLevel <arg>    log level\n" +
-                     "     --password <arg>    the password to use for authentication\n" +
-                     "     --username <arg>    the username to use for authentication\n", actual);
+        assertEquals("usage: thermostat usage of test command\n" +
+                     "                  description of test command\n" +
+                     "thermostat test1\n\n", actual);
     }
 
     @Test
     public void verifyHelpKnownCmdPrintsCommandUsageSorted() {
-
-        CommandInfoSource infos = mock(CommandInfoSource.class);
-        Collection<CommandInfo> infoList = new ArrayList<CommandInfo>();
+        CommandInfo helpInfo = mock(CommandInfo.class);
+        when(helpInfo.getName()).thenReturn("help");
+        when(helpInfo.getDescription()).thenReturn("show help");
         
         CommandInfo info1 = mock(CommandInfo.class);
         when(info1.getName()).thenReturn("test1");
         when(info1.getDescription()).thenReturn("test command 1");
-        infoList.add(info1);
 
         CommandInfo info2 = mock(CommandInfo.class);
         when(info2.getName()).thenReturn("test2");
         when(info2.getDescription()).thenReturn("test command 2");
-        infoList.add(info2);
 
         CommandInfo info3 = mock(CommandInfo.class);
         when(info3.getName()).thenReturn("test3");
         when(info3.getDescription()).thenReturn("test command 3");
-        infoList.add(info3);
 
         CommandInfo info4 = mock(CommandInfo.class);
         when(info4.getName()).thenReturn("test4");
         when(info4.getDescription()).thenReturn("test command 4");
-        infoList.add(info4);
 
-        when(infos.getCommandInfos()).thenReturn(infoList);
-        mockCommandInfoSourceService(infos);
+        when(infos.getCommandInfos()).thenReturn(Arrays.asList(info2, helpInfo, info4, info3, info1));
 
         HelpCommand cmd = new HelpCommand();
+        cmd.setCommandInfoSource(infos);
         Arguments args = mock(Arguments.class);
         when(args.getNonOptionArguments()).thenReturn(new ArrayList<String>());
         cmd.run(ctxFactory.createContext(args));
 
         String actual = ctxFactory.getOutput();
         String expected = "list of commands:\n\n"
+                + " help          show help\n"
                 + " test1         test command 1\n"
                 + " test2         test command 2\n"
                 + " test3         test command 3\n"
@@ -214,39 +209,12 @@
         assertEquals(expected, actual);
     }
 
-    // TODO bug wrt CommonCommandOptions makes this test fail.
-    @Ignore
     @Test
-    public void verifyHelpKnownStorageCmdPrintsCommandUsageWithDbUrl() {
-        TestCommand cmd1 = new TestCommand("test1");
-        String usage = "test usage command 1";
-        cmd1.setUsage(usage);
-        cmd1.setStorageRequired(true);
-        ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1));
+    public void verifyHelpUnknownCmdPrintsSummaries() {
+        when(infos.getCommandInfo("test1")).thenThrow(new CommandInfoNotFoundException("test1"));
 
         HelpCommand cmd = new HelpCommand();
-        Arguments args = mock(Arguments.class);
-        when(args.getNonOptionArguments()).thenReturn(Arrays.asList("test1"));
-        cmd.run(ctxFactory.createContext(args));
-
-        String actual = ctxFactory.getOutput();
-        assertEquals("usage: test1 [--logLevel <arg>] [--password <arg>] [--username <arg>]\n" +
-                     "test usage command 1\n" +
-                     "  -d,--dbUrl <arg>       the URL of the storage to connect to\n" +
-                     "     --logLevel <arg>    log level\n" +
-                     "     --password <arg>    the password to use for authentication\n" +
-                     "     --username <arg>    the username to use for authentication\n", actual);
-    }
-
-    @Test
-    public void verifyHelpUnknownCmdPrintsSummaries() {
-
-        CommandInfoSource infos = mock(CommandInfoSource.class);
-        
-        when(infos.getCommandInfo("test1")).thenThrow(new CommandInfoNotFoundException("test1"));
-        mockCommandInfoSourceService(infos);
-
-        HelpCommand cmd = new HelpCommand();
+        cmd.setCommandInfoSource(infos);
         SimpleArguments args = new SimpleArguments();
         args.addNonOptionArgument("test1");
         cmd.run(ctxFactory.createContext(args));
@@ -258,11 +226,5 @@
         assertEquals(expected, actual);
     }
 
-    @Test
-    public void testDescAndUsage() {
-        HelpCommand cmd = new HelpCommand();
-        assertNotNull(cmd.getDescription());
-        assertNotNull(cmd.getUsage());
-    }
 }
 
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java	Tue Jan 29 14:47:23 2013 +0100
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java	Tue Jan 29 10:24:50 2013 -0500
@@ -217,7 +217,9 @@
         when(helpCommandInfo.getOptions()).thenReturn(new Options());
         when(helpCommandInfo.getUsage()).thenReturn("thermostat help");
 
-        ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(new HelpCommand(), cmd1, cmd2, cmd3, basicCmd));
+        HelpCommand helpCommand = new HelpCommand();
+
+        ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(helpCommand, cmd1, cmd2, cmd3, basicCmd));
 
         registry = mock(BundleManager.class);
 
@@ -236,14 +238,9 @@
         infoList.add(info3);
         when(infos.getCommandInfos()).thenReturn(infoList);
 
+        helpCommand.setCommandInfoSource(infos);
+
         PowerMockito.mockStatic(FrameworkUtil.class);
-        Bundle bundle = mock(Bundle.class);
-        BundleContext bCtx = mock(BundleContext.class);
-        when(bundle.getBundleContext()).thenReturn(bCtx);
-        ServiceReference infosRef = mock(ServiceReference.class);
-        when(bCtx.getServiceReference(CommandInfoSource.class)).thenReturn(infosRef);
-        when(bCtx.getService(infosRef)).thenReturn(infos);
-        when(FrameworkUtil.getBundle(isA(HelpCommand.class.getClass()))).thenReturn(bundle);
 
         storage = mock(Storage.class);
         ServiceReference storageRef = mock(ServiceReference.class);