Wednesday, May 31, 2017

Delimiters in ST4's imports

A rule: 

Template files that are being imported should explicitly specify delimiters.  

If they don't, the delimiters of the file that has import statement will be used. If these delimiters are different from the delimiters of the imported file, the template will not be properly rendered.

Sunday, May 21, 2017

Testing Content Providers with Robolectric

There are many samples of testing content providers with Robolectric that seem incorrect.  They would instantiate content provider directly, manually call onCreate(), and then register the provider with the shadow content resolver.  But when you do this, the provider's getContext() will return null if you call it from within onCreate() method.

What seems to work is the following:

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class)
public class ProviderTestJUnit {
    private static final String AUTHORITY = “com.example.provider";
    private Context context;

    @Before
    public void setUp() {
        context = RuntimeEnvironment.application;
        ShadowContentResolver.registerProviderInternal(AUTHORITY,
                Robolectric.setupContentProvider(Provider.class));
    }

    @Test
    public void simpleQuery() {
        final ContentResolver cr = context.getContentResolver();
        final Uri uri = new Uri.Builder()
                .scheme(ContentResolver.SCHEME_CONTENT)
                .authority(AUTHORITY).build();
        final Cursor cursor = cr.query(uri, null, null, null, null);
        assertNotNull(cursor);
    }
}

When you call ShadowContentResolver.registerProviderInternal(), the content provider is created, properly initialized, and then its onCreate() is called.  Calling getContext() from within onCreate() will return non-null context.

After simple setUp() initialization the test will run.  The test code looks the same as if you tested your provider on an emulator or a device.


Saturday, May 20, 2017

Testing Content Providers (again)

This earlier post describes how to fix content provider tests.  Another way to fix them is to make setUp() method public and annotate it with @Before attribute:

@Before
@Override
public void setUp() throws Exception {
    setContext(InstrumentationRegistry.getTargetContext());
    super.setUp();
}

Note that the method should be implemented as described Testing Your Content Provider.

Listing folders first in OSX Finder

A short version of the original post:


Saturday, April 8, 2017

Loaders 1.2.0 is released

A new version of the loaders library, 1.2.0, which now also works with Loaders from Android support library, is released.
A sample application that demonstrates the usage of the library was also released today.

Saturday, March 18, 2017

SELECT LIKE FROM LIKE WHERE LIKE LIKE LIKE

SQLite documentation clearly says about not using keywords as the names of named objects.  For example, using a keyword as a table name

CREATE TABLE UNIQUE (
    a TEXT
);

leads to the following syntax error:

Error while executing SQL query on database 'provider': near "UNIQUE": syntax error

But this is not true for all keywords.  Let's try LIKE as a table name:

CREATE TABLE LIKE (
    a TEXT
);

No error, the table is created.  Let's try LIKE as a column name:

CREATE TABLE LIKE (
    LIKE TEXT
);

No problem.

INSERT INTO LIKE (LIKE) VALUES('LIKE');

Also works.  And now is the best example:

SELECT LIKE FROM LIKE WHERE LIKE LIKE LIKE;

Compiles, runs and returns correct results.  You don't even need to put quotes around the last LIKE.


Friday, March 17, 2017

Making Antlr4 fail on a syntax error

When Antlr4 encounter a syntax error, it emits an error message and then attempts to recover and continue parsing.  This default strategy is good for normal use but does not work for unit testing where we want the parser to throw an exception on syntax error so that the unit test actually fails.

To make Antlr4 fail on syntax error, we need to extend BaseErrorListener as follows:

class FailingErrorListener extends BaseErrorListener {
    @Override
    public void syntaxError(Recognizer<?, ?> recognizer,
            Object offendingSymbol, int line,
            int charPositionInLine, String msg,
            RecognitionException e)
            throws ParseCancellationException {
        throw new ParseCancellationException("line " + line + 
            ":" + charPositionInLine + " " + msg);
    }
}

Then, we need to add this error listener to both a lexer and a parser:

final ANTLRInputStream input = new ANTLRInputStream(stream);
final FailingErrorListener errorListener = new FailingErrorListener();

final MyLexer lexer = new MyLexer(input);
lexer.removeErrorListeners();
lexer.addErrorListener(errorListener);

final CommonTokenStream tokens = new CommonTokenStream(lexer);

final MyParser parser = new MyParser(tokens);
parser.removeErrorListeners();
parser.addErrorListener(errorListener);

After these changes the parser starts failing on as soon as it encounters a syntax error.