diff --git a/app/src/main/java/dnd/jon/spellbook/SpellCodec.java b/app/src/main/java/dnd/jon/spellbook/SpellCodec.java index 99f056cf..3f1c3d50 100755 --- a/app/src/main/java/dnd/jon/spellbook/SpellCodec.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellCodec.java @@ -83,7 +83,7 @@ Spell parseSpell(JSONObject json, SpellBuilder b, boolean useInternal) throws JS .setName(json.getString(NAME_KEY)) .setRange(rangeGetter.apply(json.getString(RANGE_KEY))) .setRitual(json.optBoolean(RITUAL_KEY, false)) - .setLevel(json.getInt(LEVEL_KEY)) + .setLevel(json.optInt(LEVEL_KEY, 0)) .setMaterial(json.optString(MATERIAL_KEY, "")) .setRoyalty(json.optString(ROYALTY_KEY, "")) .setDescription(json.getString(DESCRIPTION_KEY)) @@ -126,21 +126,23 @@ Spell parseSpell(JSONObject json, SpellBuilder b, boolean useInternal) throws JS // Components boolean[] components = { false, false, false, false }; - JSONArray componentsArray = json.getJSONArray(COMPONENTS_KEY); - for (int i = 0; i < componentsArray.length(); ++i) { - final char c = componentsArray.getString(i).charAt(0); - switch (c) { - case 'V': - components[0] = true; - break; - case 'S': - components[1] = true; - break; - case 'M': - components[2] = true; - break; - case 'R': - components[3] = true; + final JSONArray componentsArray = json.optJSONArray(COMPONENTS_KEY); + if (componentsArray != null) { + for (int i = 0; i < componentsArray.length(); ++i) { + final char c = componentsArray.getString(i).charAt(0); + switch (c) { + case 'V': + components[0] = true; + break; + case 'S': + components[1] = true; + break; + case 'M': + components[2] = true; + break; + case 'R': + components[3] = true; + } } } b.setComponents(components); diff --git a/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java b/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java index 29f14729..a8c115d3 100644 --- a/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java +++ b/app/src/main/java/dnd/jon/spellbook/SpellbookViewModel.java @@ -1183,7 +1183,7 @@ boolean loadCreatedContent(JSONObject json) { try { final Spell spell = codec.parseSpell(spellJSON, builder, false); addCreatedSpell(spell); - } catch (JSONException e) { + } catch (JSONException | NullPointerException e) { Log.e(LOGGING_TAG, e.getMessage()); anyFailures = true; } diff --git a/app/src/test/java/dnd/jon/spellbook/SpellTest.java b/app/src/test/java/dnd/jon/spellbook/SpellTest.java index 2a67c4da..c8d223e9 100644 --- a/app/src/test/java/dnd/jon/spellbook/SpellTest.java +++ b/app/src/test/java/dnd/jon/spellbook/SpellTest.java @@ -14,7 +14,10 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; +import java.util.Arrays; import java.util.Locale; +import java.util.stream.IntStream; +import java.util.stream.Stream; @RunWith(RobolectricTestRunner.class) @@ -108,4 +111,84 @@ public void spellParsePtTest() { Assert.fail(); } } + + @Test + @Config(sdk = 34) + public void spellParseNoLevel() { + final String jsonString = "{ \"id\": 100000, \"name\": \"Test Spell\", \"desc\": \"abcde\", \"higher_level\": \"fghij\", \"range\": \"2 foot\", \"material\": \"\", \"royalty\": \"\", \"ritual\": true, \"duration\": \"3 minute\", \"concentration\": false, \"casting_time\": \"action\", \"school\": \"Evocation\", \"locations\": [], \"components\": [ \"V\", \"S\" ], \"classes\": [ \"Artificer\", \"Paladin\" ], \"subclasses\": [], \"tce_expanded_classes\": [] }"; + try { + final JSONObject json = new JSONObject(jsonString); + final Context context = InstrumentationRegistry.getInstrumentation().getContext(); + final SpellCodec codec = new SpellCodec(context); + final SpellBuilder builder = new SpellBuilder(context); + final Spell spell = codec.parseSpell(json, builder, true); + + Truth.assertThat(spell.getLevel()).isEqualTo(0); + } catch (JSONException e) { + e.printStackTrace(); + Assert.fail(); + } + } + + @Test + @Config(sdk = 34) + public void spellParseNoLevelPt() { + final String jsonString = "{ \"id\": 100000, \"name\": \"Test Spell\", \"desc\": \"abcde\", \"higher_level\": \"fghij\", \"range\": \"2 foot\", \"material\": \"\", \"royalty\": \"\", \"ritual\": true, \"duration\": \"3 minute\", \"concentration\": false, \"casting_time\": \"action\", \"school\": \"Evocation\", \"locations\": [], \"components\": [ \"V\", \"S\" ], \"classes\": [ \"Artificer\", \"Paladin\" ], \"subclasses\": [], \"tce_expanded_classes\": [] }"; + try { + final JSONObject json = new JSONObject(jsonString); + final Context instrumentationContext = InstrumentationRegistry.getInstrumentation().getContext(); + final Context context = LocalizationUtils.getLocalizedContext(instrumentationContext, new Locale("pt")); + final SpellCodec codec = new SpellCodec(context); + final SpellBuilder builder = new SpellBuilder(context); + final Spell spell = codec.parseSpell(json, builder, true); + + Truth.assertThat(spell.getLevel()).isEqualTo(0); + } catch (JSONException e) { + e.printStackTrace(); + Assert.fail(); + } + } + + @Test + @Config(sdk = 34) + public void spellParseNoComponents() { + final String jsonString = "{ \"id\": 100000, \"name\": \"Test Spell\", \"desc\": \"abcde\", \"higher_level\": \"fghij\", \"range\": \"2 foot\", \"material\": \"\", \"royalty\": \"\", \"ritual\": true, \"duration\": \"3 minute\", \"concentration\": false, \"casting_time\": \"action\", \"level\": 2, \"school\": \"Evocation\", \"locations\": [], \"classes\": [ \"Artificer\", \"Paladin\" ], \"subclasses\": [], \"tce_expanded_classes\": [] }"; + try { + final JSONObject json = new JSONObject(jsonString); + final Context context = InstrumentationRegistry.getInstrumentation().getContext(); + final SpellCodec codec = new SpellCodec(context); + final SpellBuilder builder = new SpellBuilder(context); + final Spell spell = codec.parseSpell(json, builder, true); + + final boolean[] components = spell.getComponents(); + Truth.assertThat(IntStream.range(0, components.length) + .mapToObj(i -> components[i]) + .noneMatch(b -> b)).isTrue(); + } catch (JSONException e) { + e.printStackTrace(); + Assert.fail(); + } + } + + @Test + @Config(sdk = 34) + public void spellParseNoComponentsPt() { + final String jsonString = "{ \"id\": 100000, \"name\": \"Test Spell\", \"desc\": \"abcde\", \"higher_level\": \"fghij\", \"range\": \"2 foot\", \"material\": \"\", \"royalty\": \"\", \"ritual\": true, \"duration\": \"3 minute\", \"concentration\": false, \"casting_time\": \"action\", \"level\": 2, \"school\": \"Evocation\", \"locations\": [], \"classes\": [ \"Artificer\", \"Paladin\" ], \"subclasses\": [], \"tce_expanded_classes\": [] }"; + try { + final JSONObject json = new JSONObject(jsonString); + final Context instrumentationContext = InstrumentationRegistry.getInstrumentation().getContext(); + final Context context = LocalizationUtils.getLocalizedContext(instrumentationContext, new Locale("pt")); + final SpellCodec codec = new SpellCodec(context); + final SpellBuilder builder = new SpellBuilder(context); + final Spell spell = codec.parseSpell(json, builder, true); + + final boolean[] components = spell.getComponents(); + Truth.assertThat(IntStream.range(0, components.length) + .mapToObj(i -> components[i]) + .noneMatch(b -> b)).isTrue(); + } catch (JSONException e) { + e.printStackTrace(); + Assert.fail(); + } + } }