Rewrote menu handling for vie custom call.

The intended trajectory of this patch is to abstract out all i/o for custom_call.
The reason is that kjellander@ will need to be able to configure custom calls using
flags, and using the same framework to gather all input gathering to a single place
will make this a lot easier.

This patch focuses on choices. The next will focus on field entries, like "enter
ip address" or "enter port number."

BUG=
TEST=Manually tested all menus in custom call, ran new unit tests.

Review URL: https://webrtc-codereview.appspot.com/757005

git-svn-id: http://webrtc.googlecode.com/svn/trunk@2758 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
phoglund@webrtc.org
2012-09-12 15:59:22 +00:00
parent ed2e2eecae
commit f72943dadc
5 changed files with 610 additions and 520 deletions

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "video_engine/test/auto_test/primitives/choice_helpers.h"
#include <cassert>
#include <cstdio>
namespace webrtc {
static const int kNoDefault = 0;
ChoiceBuilder::ChoiceBuilder(const Choices& choices)
: choices_(choices), default_choice_(kNoDefault), input_source_(stdin) {
}
int ChoiceBuilder::Choose() {
if (!title_.empty()) {
printf("\n%s\n", title_.c_str());
}
Choices::const_iterator iterator = choices_.begin();
for (int number = 1; iterator != choices_.end(); ++iterator, ++number)
printf(" %d. %s\n", number, (*iterator).c_str());
if (default_choice_ != kNoDefault)
printf(" Hit enter for default (%s):\n", default_choice_text_.c_str());
printf("# ");
char input[8];
fgets(input, 8, input_source_);
int selection;
if (input[0] == '\n')
selection = default_choice_;
else
selection = atoi(input);
if (selection < 1 || selection > static_cast<int>(choices_.size())) {
printf("Please select one of the given options.\n");
return Choose();
}
return selection;
}
ChoiceBuilder& ChoiceBuilder::WithDefault(const std::string& default_choice) {
Choices::const_iterator iterator = std::find(
choices_.begin(), choices_.end(), default_choice);
assert(iterator != choices_.end() && "No such choice.");
// Store the value as the choice number, e.g. its index + 1.
default_choice_ = (iterator - choices_.begin()) + 1;
default_choice_text_ = default_choice;
return *this;
}
ChoiceBuilder& ChoiceBuilder::WithInputSource(FILE* input_source) {
input_source_ = input_source;
return *this;
}
ChoiceBuilder& ChoiceBuilder::WithTitle(const std::string& title) {
title_ = title;
return *this;
}
Choices SplitChoices(const std::string& raw_choices) {
Choices result;
size_t current_pos = 0;
size_t next_newline = 0;
while ((next_newline = raw_choices.find('\n', current_pos)) !=
std::string::npos) {
std::string choice = raw_choices.substr(
current_pos, next_newline - current_pos);
result.push_back(choice);
current_pos = next_newline + 1;
}
std::string last_choice = raw_choices.substr(current_pos);
if (!last_choice.empty())
result.push_back(last_choice);
return result;
}
ChoiceBuilder FromChoices(const std::string& raw_choices) {
return ChoiceBuilder(SplitChoices(raw_choices));
}
} // namespace webrtc

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_VIDEO_ENGINE_TEST_AUTO_TEST_PRIMITIVES_CHOICE_HELPERS_H_
#define WEBRTC_VIDEO_ENGINE_TEST_AUTO_TEST_PRIMITIVES_CHOICE_HELPERS_H_
#include <string>
#include <vector>
namespace webrtc {
typedef std::vector<std::string> Choices;
/**
* Used to ask the user to make a choice. This class will allow you to
* configure how to ask the question, and then ask it. For instance,
*
* int choice = FromChoices("Choice 1\n"
* "Choice 2\n").WithDefault("Choice 1").Choose();
*
* will print a menu presenting the two choices and ask for input. The user,
* can input 1, 2 or just hit enter since we specified a default in this case.
* The Choose call will block until the user gives valid input one way or the
* other. The choice variable is guaranteed to contain either 1 or 2 after
* this particular call.
*
* The class uses stdout and stdin by default, but stdin can be replaced using
* WithInputSource for unit tests.
*/
class ChoiceBuilder {
public:
explicit ChoiceBuilder(const Choices& choices);
// Specifies the choice as the default. The choice must be one of the choices
// passed in the constructor. If this method is not called, the user has to
// choose an option explicitly.
ChoiceBuilder& WithDefault(const std::string& default_choice);
// Replaces the input source where we ask for input. Default is stdin.
ChoiceBuilder& WithInputSource(FILE* input_source);
// Prints a title above the choice list when the choice is made.
ChoiceBuilder& WithTitle(const std::string& title);
// Prints the choice list and requests input from the input source. Returns
// the choice number (choices start at 1).
int Choose();
private:
Choices choices_;
int default_choice_;
std::string default_choice_text_;
std::string title_;
FILE* input_source_;
};
// Convenience function that creates a choice builder given a string where
// choices are separated by \n.
ChoiceBuilder FromChoices(const std::string& raw_choices);
// Creates choices from a string where choices are separated by \n.
Choices SplitChoices(const std::string& raw_choices);
} // namespace webrtc
#endif // CHOICE_HELPERS_H_

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <cstdio>
#include "gtest/gtest.h"
#include "video_engine/test/auto_test/primitives/choice_helpers.h"
namespace {
FILE* FakeStdin(const std::string& input) {
FILE* fake_stdin = tmpfile();
EXPECT_EQ(input.size(),
fwrite(input.c_str(), sizeof(char), input.size(), fake_stdin));
rewind(fake_stdin);
return fake_stdin;
}
} // namespace
namespace webrtc {
class ChoiceHelpersTest : public testing::Test {
};
TEST_F(ChoiceHelpersTest, SplitReturnsEmptyChoicesForEmptyInput) {
EXPECT_TRUE(SplitChoices("").empty());
}
TEST_F(ChoiceHelpersTest, SplitHandlesSingleChoice) {
Choices choices = SplitChoices("Single Choice");
EXPECT_EQ(1u, choices.size());
EXPECT_EQ("Single Choice", choices[0]);
}
TEST_F(ChoiceHelpersTest, SplitHandlesSingleChoiceWithEndingNewline) {
Choices choices = SplitChoices("Single Choice\n");
EXPECT_EQ(1u, choices.size());
EXPECT_EQ("Single Choice", choices[0]);
}
TEST_F(ChoiceHelpersTest, SplitHandlesMultipleChoices) {
Choices choices = SplitChoices(
"Choice 1\n"
"Choice 2\n"
"Choice 3");
EXPECT_EQ(3u, choices.size());
EXPECT_EQ("Choice 1", choices[0]);
EXPECT_EQ("Choice 2", choices[1]);
EXPECT_EQ("Choice 3", choices[2]);
}
TEST_F(ChoiceHelpersTest, SplitHandlesMultipleChoicesWithEndingNewline) {
Choices choices = SplitChoices(
"Choice 1\n"
"Choice 2\n"
"Choice 3\n");
EXPECT_EQ(3u, choices.size());
EXPECT_EQ("Choice 1", choices[0]);
EXPECT_EQ("Choice 2", choices[1]);
EXPECT_EQ("Choice 3", choices[2]);
}
TEST_F(ChoiceHelpersTest, CanSelectUsingChoiceBuilder) {
FILE* fake_stdin = FakeStdin("1\n2\n");
EXPECT_EQ(1, FromChoices("Choice 1\n"
"Choice 2").WithInputSource(fake_stdin).Choose());
EXPECT_EQ(2, FromChoices("Choice 1\n"
"Choice 2").WithInputSource(fake_stdin).Choose());
fclose(fake_stdin);
}
TEST_F(ChoiceHelpersTest, RetriesIfGivenInvalidChoice) {
FILE* fake_stdin = FakeStdin("3\n0\n99\n23409234809\na\nwhatever\n1\n");
EXPECT_EQ(1, FromChoices("Choice 1\n"
"Choice 2").WithInputSource(fake_stdin).Choose());
fclose(fake_stdin);
}
TEST_F(ChoiceHelpersTest, RetriesOnEnterIfNoDefaultSet) {
FILE* fake_stdin = FakeStdin("\n2\n");
EXPECT_EQ(2, FromChoices("Choice 1\n"
"Choice 2").WithInputSource(fake_stdin).Choose());
fclose(fake_stdin);
}
TEST_F(ChoiceHelpersTest, PicksDefaultOnEnterIfDefaultSet) {
FILE* fake_stdin = FakeStdin("\n");
EXPECT_EQ(2, FromChoices("Choice 1\n"
"Choice 2").WithInputSource(fake_stdin)
.WithDefault("Choice 2").Choose());
fclose(fake_stdin);
}
} // namespace webrtc

View File

@ -57,6 +57,9 @@
# Test primitives
'primitives/base_primitives.cc',
'primitives/base_primitives.h',
'primitives/choice_helpers.cc',
'primitives/choice_helpers.h',
'primitives/choice_helpers_unittest.cc',
'primitives/codec_primitives.cc',
'primitives/codec_primitives.h',
'primitives/framedrop_primitives.h',