diff options
9 files changed, 192 insertions, 96 deletions
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml index 5f05e8b18..e14862206 100644 --- a/java/res/xml/method.xml +++ b/java/res/xml/method.xml @@ -28,7 +28,7 @@ be_BY: Belarusian (Belarus)/east_slavic bg: Bulgarian/bulgarian bg: Bulgarian/bulgarian_bds - bn_BD: Bengali (Bangladesh)/bengali_akkhor # This is a preliminary keyboard layout. + bn_BD: Bengali (Bangladesh)/bengali_akkhor bn_IN: Bengali (India)/bengali ca: Catalan/spanish cs: Czech/qwertz @@ -181,8 +181,6 @@ android:imeSubtypeExtraValue="KeyboardLayoutSet=bulgarian_bds,EmojiCapable" android:isAsciiCapable="false" /> - <!-- TODO: This Bengali (Bangladesh) keyboard is a preliminary layout. - This isn't based on the final specification. --> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0xa2144b0c" diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index b07693c76..01980ea6e 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -25,7 +25,6 @@ import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.PorterDuff; import android.graphics.Rect; -import android.graphics.Region; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.graphics.drawable.NinePatchDrawable; @@ -41,6 +40,7 @@ import com.android.inputmethod.latin.utils.TypefaceUtils; import java.util.HashSet; +import javax.annotation.Nonnull; import javax.annotation.Nullable; /** @@ -100,6 +100,8 @@ public class KeyboardView extends View { private static final float MAX_LABEL_RATIO = 0.90f; // Main keyboard + // TODO: Consider having a dummy keyboard object to make this @Nonnull + @Nullable private Keyboard mKeyboard; protected final KeyDrawParams mKeyDrawParams = new KeyDrawParams(); @@ -108,14 +110,14 @@ public class KeyboardView extends View { private boolean mInvalidateAllKeys; /** The keys that should be drawn */ private final HashSet<Key> mInvalidatedKeys = new HashSet<>(); - /** The working rectangle variable */ - private final Rect mWorkingRect = new Rect(); + /** The working rectangle for clipping */ + private final Rect mClipRect = new Rect(); /** The keyboard bitmap buffer for faster updates */ - /** The clip region to draw keys */ - private final Region mClipRegion = new Region(); private Bitmap mOffscreenBuffer; /** The canvas for the above mutable keyboard bitmap */ + @Nonnull private final Canvas mOffscreenCanvas = new Canvas(); + @Nonnull private final Paint mPaint = new Paint(); private final Paint.FontMetrics mFontMetrics = new Paint.FontMetrics(); public KeyboardView(final Context context, final AttributeSet attrs) { @@ -161,11 +163,12 @@ public class KeyboardView extends View { mPaint.setAntiAlias(true); } + @Nullable public KeyVisualAttributes getKeyVisualAttribute() { return mKeyVisualAttributes; } - private static void blendAlpha(final Paint paint, final int alpha) { + private static void blendAlpha(@Nonnull final Paint paint, final int alpha) { final int color = paint.getColor(); paint.setARGB((paint.getAlpha() * alpha) / Constants.Color.ALPHA_OPAQUE, Color.red(color), Color.green(color), Color.blue(color)); @@ -184,7 +187,7 @@ public class KeyboardView extends View { * @see #getKeyboard() * @param keyboard the keyboard to display in this view */ - public void setKeyboard(final Keyboard keyboard) { + public void setKeyboard(@Nonnull final Keyboard keyboard) { mKeyboard = keyboard; final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap; mKeyDrawParams.updateParams(keyHeight, mKeyVisualAttributes); @@ -198,6 +201,7 @@ public class KeyboardView extends View { * @return the currently attached keyboard * @see #setKeyboard(Keyboard) */ + @Nullable public Keyboard getKeyboard() { return mKeyboard; } @@ -212,13 +216,14 @@ public class KeyboardView extends View { @Override protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { - if (mKeyboard == null) { + final Keyboard keyboard = getKeyboard(); + if (keyboard == null) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); return; } // The main keyboard expands to the entire this {@link KeyboardView}. - final int width = mKeyboard.mOccupiedWidth + getPaddingLeft() + getPaddingRight(); - final int height = mKeyboard.mOccupiedHeight + getPaddingTop() + getPaddingBottom(); + final int width = keyboard.mOccupiedWidth + getPaddingLeft() + getPaddingRight(); + final int height = keyboard.mOccupiedHeight + getPaddingTop() + getPaddingBottom(); setMeasuredDimension(width, height); } @@ -266,52 +271,45 @@ public class KeyboardView extends View { } } - private void onDrawKeyboard(final Canvas canvas) { - if (mKeyboard == null) return; + private void onDrawKeyboard(@Nonnull final Canvas canvas) { + final Keyboard keyboard = getKeyboard(); + if (keyboard == null) { + return; + } - final int width = getWidth(); - final int height = getHeight(); final Paint paint = mPaint; - + final Drawable background = getBackground(); // Calculate clip region and set. final boolean drawAllKeys = mInvalidateAllKeys || mInvalidatedKeys.isEmpty(); final boolean isHardwareAccelerated = canvas.isHardwareAccelerated(); // TODO: Confirm if it's really required to draw all keys when hardware acceleration is on. if (drawAllKeys || isHardwareAccelerated) { - mClipRegion.set(0, 0, width, height); - } else { - mClipRegion.setEmpty(); - for (final Key key : mInvalidatedKeys) { - if (mKeyboard.hasKey(key)) { - final int x = key.getX() + getPaddingLeft(); - final int y = key.getY() + getPaddingTop(); - mWorkingRect.set(x, y, x + key.getWidth(), y + key.getHeight()); - mClipRegion.union(mWorkingRect); - } - } - } - if (!isHardwareAccelerated) { - canvas.clipRegion(mClipRegion, Region.Op.REPLACE); - // Draw keyboard background. - canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR); - final Drawable background = getBackground(); - if (background != null) { + if (!isHardwareAccelerated && background != null) { + // Need to draw keyboard background on {@link #mOffscreenBuffer}. + canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR); background.draw(canvas); } - } - - // TODO: Confirm if it's really required to draw all keys when hardware acceleration is on. - if (drawAllKeys || isHardwareAccelerated) { // Draw all keys. - for (final Key key : mKeyboard.getSortedKeys()) { + for (final Key key : keyboard.getSortedKeys()) { onDrawKey(key, canvas, paint); } } else { - // Draw invalidated keys. for (final Key key : mInvalidatedKeys) { - if (mKeyboard.hasKey(key)) { - onDrawKey(key, canvas, paint); + if (!keyboard.hasKey(key)) { + continue; } + if (background != null) { + // Need to redraw key's background on {@link #mOffscreenBuffer}. + final int x = key.getX() + getPaddingLeft(); + final int y = key.getY() + getPaddingTop(); + mClipRect.set(x, y, x + key.getWidth(), y + key.getHeight()); + canvas.save(); + canvas.clipRect(mClipRect); + canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR); + background.draw(canvas); + canvas.restore(); + } + onDrawKey(key, canvas, paint); } } @@ -319,20 +317,22 @@ public class KeyboardView extends View { mInvalidateAllKeys = false; } - private void onDrawKey(final Key key, final Canvas canvas, final Paint paint) { + private void onDrawKey(@Nonnull final Key key, @Nonnull final Canvas canvas, + @Nonnull final Paint paint) { final int keyDrawX = key.getDrawX() + getPaddingLeft(); final int keyDrawY = key.getY() + getPaddingTop(); canvas.translate(keyDrawX, keyDrawY); - final int keyHeight = mKeyboard.mMostCommonKeyHeight - mKeyboard.mVerticalGap; final KeyVisualAttributes attr = key.getVisualAttributes(); - final KeyDrawParams params = mKeyDrawParams.mayCloneAndUpdateParams(keyHeight, attr); + final KeyDrawParams params = mKeyDrawParams.mayCloneAndUpdateParams(key.getHeight(), attr); params.mAnimAlpha = Constants.Color.ALPHA_OPAQUE; if (!key.isSpacer()) { final Drawable background = key.selectBackgroundDrawable( mKeyBackground, mFunctionalKeyBackground, mSpacebarBackground); - onDrawKeyBackground(key, canvas, background); + if (background != null) { + onDrawKeyBackground(key, canvas, background); + } } onDrawKeyTopVisuals(key, canvas, paint, params); @@ -340,8 +340,8 @@ public class KeyboardView extends View { } // Draw key background. - protected void onDrawKeyBackground(final Key key, final Canvas canvas, - final Drawable background) { + protected void onDrawKeyBackground(@Nonnull final Key key, @Nonnull final Canvas canvas, + @Nonnull final Drawable background) { final int keyWidth = key.getDrawWidth(); final int keyHeight = key.getHeight(); final int bgWidth, bgHeight, bgX, bgY; @@ -373,15 +373,17 @@ public class KeyboardView extends View { } // Draw key top visuals. - protected void onDrawKeyTopVisuals(final Key key, final Canvas canvas, final Paint paint, - final KeyDrawParams params) { + protected void onDrawKeyTopVisuals(@Nonnull final Key key, @Nonnull final Canvas canvas, + @Nonnull final Paint paint, @Nonnull final KeyDrawParams params) { final int keyWidth = key.getDrawWidth(); final int keyHeight = key.getHeight(); final float centerX = keyWidth * 0.5f; final float centerY = keyHeight * 0.5f; // Draw key label. - final Drawable icon = key.getIcon(mKeyboard.mIconsSet, params.mAnimAlpha); + final Keyboard keyboard = getKeyboard(); + final Drawable icon = (keyboard == null) ? null + : key.getIcon(keyboard.mIconsSet, params.mAnimAlpha); float labelX = centerX; float labelBaseline = centerY; final String label = key.getLabel(); @@ -500,8 +502,8 @@ public class KeyboardView extends View { } // Draw popup hint "..." at the bottom right corner of the key. - protected void drawKeyPopupHint(final Key key, final Canvas canvas, final Paint paint, - final KeyDrawParams params) { + protected void drawKeyPopupHint(@Nonnull final Key key, @Nonnull final Canvas canvas, + @Nonnull final Paint paint, @Nonnull final KeyDrawParams params) { if (TextUtils.isEmpty(mKeyPopupHintLetter)) { return; } @@ -518,15 +520,15 @@ public class KeyboardView extends View { canvas.drawText(mKeyPopupHintLetter, hintX, hintY, paint); } - protected static void drawIcon(final Canvas canvas, final Drawable icon, final int x, - final int y, final int width, final int height) { + protected static void drawIcon(@Nonnull final Canvas canvas,@Nonnull final Drawable icon, + final int x, final int y, final int width, final int height) { canvas.translate(x, y); icon.setBounds(0, 0, width, height); icon.draw(canvas); canvas.translate(-x, -y); } - public Paint newLabelPaint(final Key key) { + public Paint newLabelPaint(@Nullable final Key key) { final Paint paint = new Paint(); paint.setAntiAlias(true); if (key == null) { @@ -560,7 +562,7 @@ public class KeyboardView extends View { * @see #invalidateAllKeys */ public void invalidateKey(@Nullable final Key key) { - if (key == null || mInvalidateAllKeys) { + if (mInvalidateAllKeys || key == null) { return; } mInvalidatedKeys.add(key); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java index 70e116709..973e956db 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java @@ -106,15 +106,17 @@ public final class KeyboardState { @Override public String toString() { - if (!mIsValid) return "INVALID"; + if (!mIsValid) { + return "INVALID"; + } if (mIsAlphabetMode) { - if (mIsAlphabetShiftLocked) return "ALPHABET_SHIFT_LOCKED"; - return "ALPHABET_" + shiftModeToString(mShiftMode); - } else if (mIsEmojiMode) { + return mIsAlphabetShiftLocked ? "ALPHABET_SHIFT_LOCKED" + : "ALPHABET_" + shiftModeToString(mShiftMode); + } + if (mIsEmojiMode) { return "EMOJI"; - } else { - return "SYMBOLS_" + shiftModeToString(mShiftMode); } + return "SYMBOLS_" + shiftModeToString(mShiftMode); } } @@ -133,9 +135,16 @@ public final class KeyboardState { mPrevSymbolsKeyboardWasShifted = false; mShiftKeyState.onRelease(); mSymbolKeyState.onRelease(); - onRestoreKeyboardState(autoCapsFlags, recapitalizeMode); + if (mSavedKeyboardState.mIsValid) { + onRestoreKeyboardState(autoCapsFlags, recapitalizeMode); + mSavedKeyboardState.mIsValid = false; + } else { + // Reset keyboard to alphabet mode. + setAlphabetKeyboard(autoCapsFlags, recapitalizeMode); + } } + // Constants for {@link SavedKeyboardState#mShiftMode} and {@link #setShifted(int)}. private static final int UNSHIFT = 0; private static final int MANUAL_SHIFT = 1; private static final int AUTOMATIC_SHIFT = 2; @@ -165,28 +174,24 @@ public final class KeyboardState { Log.d(TAG, "onRestoreKeyboardState: saved=" + state + " " + stateToString(autoCapsFlags, recapitalizeMode)); } - if (!state.mIsValid || state.mIsAlphabetMode) { - setAlphabetKeyboard(autoCapsFlags, recapitalizeMode); - } else if (state.mIsEmojiMode) { - setEmojiKeyboard(); - } else { - if (state.mShiftMode == MANUAL_SHIFT) { - setSymbolsShiftedKeyboard(); - } else { - setSymbolsKeyboard(); - } - } - - if (!state.mIsValid) return; - state.mIsValid = false; - + mPrevMainKeyboardWasShiftLocked = state.mIsAlphabetShiftLocked; if (state.mIsAlphabetMode) { + setAlphabetKeyboard(autoCapsFlags, recapitalizeMode); setShiftLocked(state.mIsAlphabetShiftLocked); if (!state.mIsAlphabetShiftLocked) { setShifted(state.mShiftMode); } + return; + } + if (state.mIsEmojiMode) { + setEmojiKeyboard(); + return; + } + // Symbol mode + if (state.mShiftMode == MANUAL_SHIFT) { + setSymbolsShiftedKeyboard(); } else { - mPrevMainKeyboardWasShiftLocked = state.mIsAlphabetShiftLocked; + setSymbolsKeyboard(); } } diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index d256f3732..e6d69a92f 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -255,7 +255,7 @@ public final class InputLogic { handler.postUpdateSuggestionStrip(SuggestedWords.INPUT_STYLE_TYPING); final String text = performSpecificTldProcessingOnTextInput(rawText); if (SpaceState.PHANTOM == mSpaceState) { - promotePhantomSpace(settingsValues); + insertAutomaticSpaceIfOptionsAndTextAllow(settingsValues); } mConnection.commitText(text, 1); StatsUtils.onWordCommitUserTyped(mEnteredText, mWordComposer.isBatchMode()); @@ -322,7 +322,7 @@ public final class InputLogic { final int firstChar = Character.codePointAt(suggestion, 0); if (!settingsValues.isWordSeparator(firstChar) || settingsValues.isUsuallyPrecededBySpace(firstChar)) { - promotePhantomSpace(settingsValues); + insertAutomaticSpaceIfOptionsAndTextAllow(settingsValues); } } @@ -584,7 +584,9 @@ public final class InputLogic { if (candidate.mSourceDict.shouldAutoCommit(candidate)) { final String[] commitParts = candidate.mWord.split(Constants.WORD_SEPARATOR, 2); batchPointers.shift(candidate.mIndexOfTouchPointOfSecondWord); - promotePhantomSpace(settingsValues); + if (SpaceState.PHANTOM == mSpaceState) { + insertAutomaticSpaceIfOptionsAndTextAllow(settingsValues); + } mConnection.commitText(commitParts[0], 0); StatsUtils.onWordCommitUserTyped(commitParts[0], mWordComposer.isBatchMode()); mSpaceState = SpaceState.PHANTOM; @@ -861,7 +863,7 @@ public final class InputLogic { // Sanity check throw new RuntimeException("Should not be composing here"); } - promotePhantomSpace(settingsValues); + insertAutomaticSpaceIfOptionsAndTextAllow(settingsValues); } if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { @@ -972,7 +974,7 @@ public final class InputLogic { } if (needsPrecedingSpace) { - promotePhantomSpace(settingsValues); + insertAutomaticSpaceIfOptionsAndTextAllow(settingsValues); } if (tryPerformDoubleSpacePeriod(event, inputTransaction)) { @@ -1961,14 +1963,14 @@ public final class InputLogic { } /** - * Promote a phantom space to an actual space. + * Insert an automatic space, if the options allow it. * - * This essentially inserts a space, and that's it. It just checks the options and the text - * before the cursor are appropriate before doing it. + * This checks the options and the text before the cursor are appropriate before inserting + * an automatic space. * * @param settingsValues the current values of the settings. */ - private void promotePhantomSpace(final SettingsValues settingsValues) { + private void insertAutomaticSpaceIfOptionsAndTextAllow(final SettingsValues settingsValues) { if (settingsValues.shouldInsertSpacesAutomatically() && settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces && !mConnection.textBeforeCursorLooksLikeURL()) { @@ -1991,7 +1993,7 @@ public final class InputLogic { } mConnection.beginBatchEdit(); if (SpaceState.PHANTOM == mSpaceState) { - promotePhantomSpace(settingsValues); + insertAutomaticSpaceIfOptionsAndTextAllow(settingsValues); } final SuggestedWordInfo autoCommitCandidate = mSuggestedWords.getAutoCommitCandidate(); // Commit except the last word for phrase gesture if the top suggestion is eligible for auto diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java index 013f024c0..0e7f4717d 100644 --- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java @@ -34,6 +34,7 @@ import java.util.HashMap; import java.util.Locale; import javax.annotation.Nonnull; +import javax.annotation.Nullable; /** * A helper class to deal with subtype locales. @@ -273,7 +274,7 @@ public final class SubtypeLocaleUtils { } @Nonnull - public static String getSubtypeNameForLogging(@Nonnull final InputMethodSubtype subtype) { + public static String getSubtypeNameForLogging(@Nullable final InputMethodSubtype subtype) { if (subtype == null) { return "<null subtype>"; } diff --git a/native/dicttoolkit/NativeFileList.mk b/native/dicttoolkit/NativeFileList.mk index d2c8c3a2c..9a547b054 100644 --- a/native/dicttoolkit/NativeFileList.mk +++ b/native/dicttoolkit/NativeFileList.mk @@ -39,5 +39,6 @@ LATIN_IME_DICT_TOOLKIT_TEST_FILES := \ $(addprefix offdevice_intermediate_dict/, \ offdevice_intermediate_dict_test.cpp) \ $(addprefix utils/, \ + arguments_parser_test.cpp \ command_utils_test.cpp \ utf8_utils_test.cpp) diff --git a/native/dicttoolkit/src/utils/arguments_parser.cpp b/native/dicttoolkit/src/utils/arguments_parser.cpp index 039dae35b..52cc7b21d 100644 --- a/native/dicttoolkit/src/utils/arguments_parser.cpp +++ b/native/dicttoolkit/src/utils/arguments_parser.cpp @@ -16,18 +16,32 @@ #include "utils/arguments_parser.h" +#include <unordered_set> + namespace latinime { namespace dicttoolkit { const int ArgumentSpec::UNLIMITED_COUNT = -1; bool ArgumentsParser::validateSpecs() const { + std::unordered_set<std::string> argumentNameSet; for (size_t i = 0; i < mArgumentSpecs.size() ; ++i) { + if (mArgumentSpecs[i].getMinCount() == 0 && mArgumentSpecs[i].getMaxCount() == 0) { + AKLOGE("minCount = maxCount = 0 for %s.", mArgumentSpecs[i].getName().c_str()); + return false; + } if (mArgumentSpecs[i].getMinCount() != mArgumentSpecs[i].getMaxCount() && i != mArgumentSpecs.size() - 1) { - AKLOGE("Variable length argument must be at the end."); + AKLOGE("Variable length argument must be at the end.", + mArgumentSpecs[i].getName().c_str()v ); + return false; + } + if (argumentNameSet.count(mArgumentSpecs[i].getName()) > 0) { + AKLOGE("Multiple arguments have the same name \"%s\".", + mArgumentSpecs[i].getName().c_str()); return false; } + argumentNameSet.insert(mArgumentSpecs[i].getName()); } return true; } diff --git a/native/dicttoolkit/src/utils/arguments_parser.h b/native/dicttoolkit/src/utils/arguments_parser.h index be2dd8749..510a8722b 100644 --- a/native/dicttoolkit/src/utils/arguments_parser.h +++ b/native/dicttoolkit/src/utils/arguments_parser.h @@ -97,8 +97,8 @@ class ArgumentSpec { class ArgumentsParser { public: - ArgumentsParser(std::unordered_map<std::string, OptionSpec> &&optionSpecs, - std::vector<ArgumentSpec> &&argumentSpecs) + ArgumentsParser(const std::unordered_map<std::string, OptionSpec> &&optionSpecs, + const std::vector<ArgumentSpec> &&argumentSpecs) : mOptionSpecs(std::move(optionSpecs)), mArgumentSpecs(std::move(argumentSpecs)) {} const ArgumentsAndOptions parseArguments(const int argc, char **argv) const; diff --git a/native/dicttoolkit/tests/utils/arguments_parser_test.cpp b/native/dicttoolkit/tests/utils/arguments_parser_test.cpp new file mode 100644 index 000000000..e79425b87 --- /dev/null +++ b/native/dicttoolkit/tests/utils/arguments_parser_test.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils/arguments_parser.h" + +#include <gtest/gtest.h> + +namespace latinime { +namespace dicttoolkit { +namespace { + +TEST(ArgumentsParserTests, TestValitadeSpecs) { + { + std::unordered_map<std::string, OptionSpec> optionSpecs; + std::vector<ArgumentSpec> argumentSpecs; + EXPECT_TRUE( + ArgumentsParser(std::move(optionSpecs), std::move(argumentSpecs)).validateSpecs()); + } + { + std::unordered_map<std::string, OptionSpec> optionSpecs; + optionSpecs["a"] = OptionSpec::keyValueOption("valueName", "default", "description"); + const std::vector<ArgumentSpec> argumentSpecs = { + ArgumentSpec::singleArgument("name", "description"), + ArgumentSpec::variableLengthArguments("name2", 0 /* minCount */, 1 /* maxCount */, + "description2") + }; + EXPECT_TRUE( + ArgumentsParser(std::move(optionSpecs), std::move(argumentSpecs)).validateSpecs()); + } + { + const std::vector<ArgumentSpec> argumentSpecs = { + ArgumentSpec::variableLengthArguments("name", 0 /* minCount */, 0 /* maxCount */, + "description") + }; + EXPECT_FALSE(ArgumentsParser(std::unordered_map<std::string, OptionSpec>(), + std::move(argumentSpecs)).validateSpecs()); + } + { + const std::vector<ArgumentSpec> argumentSpecs = { + ArgumentSpec::singleArgument("name", "description"), + ArgumentSpec::variableLengthArguments("name", 0 /* minCount */, 1 /* maxCount */, + "description") + }; + EXPECT_FALSE(ArgumentsParser(std::unordered_map<std::string, OptionSpec>(), + std::move(argumentSpecs)).validateSpecs()); + } + { + const std::vector<ArgumentSpec> argumentSpecs = { + ArgumentSpec::variableLengthArguments("name", 0 /* minCount */, 1 /* maxCount */, + "description"), + ArgumentSpec::singleArgument("name2", "description2") + }; + EXPECT_FALSE(ArgumentsParser(std::unordered_map<std::string, OptionSpec>(), + std::move(argumentSpecs)).validateSpecs()); + } +} + +} // namespace +} // namespace dicttoolkit +} // namespace latinime |