Skip to content

Commit

Permalink
Added EmailTest class
Browse files Browse the repository at this point in the history
* Added test for fixup_user_entered_email
* Fixed a couple of issues in fixup_user_entered_email
* Added wwiv::strings::contains(haystack, needle) since it
  seems generally useful.
* cleaned up a few other things here and there.
  • Loading branch information
wwiv committed Nov 7, 2020
1 parent 955f846 commit 7cf31cd
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 68 deletions.
23 changes: 12 additions & 11 deletions bbs/email.cpp
Expand Up @@ -727,27 +727,28 @@ void delmail(File& f, size_t loc) {
f.Write(&m, sizeof(mailrec));
}

std::string fixup_user_entered_email(const std::string& s) {
if (s.empty()) {
std::string fixup_user_entered_email(const std::string& user_input) {
if (user_input.empty()) {
return{};
}
auto user_input{s};
const auto at_pos = user_input.find('@');
if (at_pos != std::string::npos && at_pos < user_input.size() - 1 &&
isalpha(user_input.at(at_pos + 1))) {
if (user_input.find(INTERNET_EMAIL_FAKE_OUTBOUND_ADDRESS) != std::string::npos) {
StringLowerCase(&user_input);
user_input += INTERNET_EMAIL_FAKE_OUTBOUND_ADDRESS;
if (!contains(user_input, INTERNET_EMAIL_FAKE_OUTBOUND_ADDRESS)) {
return StrCat(ToStringLowerCase(user_input), " ", INTERNET_EMAIL_FAKE_OUTBOUND_ADDRESS);
}
} else if (user_input.find('(') != std::string::npos && user_input.find(')') != std::string::npos) {
return user_input;
}

const auto first = user_input.find_last_of('(');
const auto last = user_input.find_last_of(')');
if (first != std::string::npos && last != std::string::npos) {
// This is where we'd check for (NNNN) and add in the @NNN for the FTN networks.
const auto first = user_input.find_last_of('(');
const auto last = user_input.find_last_of(')');
if (last > first) {
const auto inner = user_input.substr(first + 1, last - first - 1);
if (inner.find('/') != std::string::npos) {
if (wwiv::stl::contains(inner, '/') && !contains(user_input, FTN_FAKE_OUTBOUND_ADDRESS)) {
// At least need a FTN address.
user_input += StrCat(" ", FTN_FAKE_OUTBOUND_ADDRESS);
return StrCat(user_input, " ", FTN_FAKE_OUTBOUND_ADDRESS);
//bout << "\r\n|#9Sending to FTN Address: |#2" << inner << wwiv::endl;
}
}
Expand Down
4 changes: 2 additions & 2 deletions bbs/email.h
Expand Up @@ -58,6 +58,6 @@ void email(const std::string& title, uint16_t user_number, uint16_t system_numbe
void imail(const std::string& title, uint16_t user_number, uint16_t system_number);
void delmail(wwiv::core::File& pFile, size_t loc);

[[nodiscard]] std::string fixup_user_entered_email(const std::string& s);
[[nodiscard]] std::string fixup_user_entered_email(const std::string& user_input);

#endif // __INCLUDED_BBS_MSGBASE_H__
#endif
1 change: 1 addition & 0 deletions bbs_test/CMakeLists.txt
Expand Up @@ -10,6 +10,7 @@ set(test_sources
bputch_test.cpp
datetime_test.cpp
dsz_test.cpp
email_test.cpp
input_test.cpp
make_abs_test.cpp
msgbase1_test.cpp
Expand Down
34 changes: 34 additions & 0 deletions bbs_test/email_test.cpp
@@ -0,0 +1,34 @@
/**************************************************************************/
/* */
/* WWIV Version 5.x */
/* Copyright (C)2014-2020, WWIV Software Services */
/* */
/* 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 "gtest/gtest.h"

#include "bbs/email.h"



TEST(EmailTest, Smoke) {
EXPECT_EQ("1", fixup_user_entered_email("1"));
EXPECT_EQ("1@1", fixup_user_entered_email("1@1"));
EXPECT_EQ("1@1.WWIVNET", fixup_user_entered_email("1@1.WWIVNET"));

EXPECT_EQ("rushfan@wwiv.us @32767", fixup_user_entered_email("rushfan@wwiv.us @32767"));
EXPECT_EQ("rushfan@wwiv.us @32767", fixup_user_entered_email("rushfan@wwiv.us"));
EXPECT_EQ("rushfan (1:1/100) @32765", fixup_user_entered_email("rushfan (1:1/100)"));
EXPECT_EQ("rushfan (1:1/100) @32765", fixup_user_entered_email("rushfan (1:1/100) @32765"));
}
43 changes: 22 additions & 21 deletions core/strings.cpp
Expand Up @@ -123,7 +123,7 @@ void SplitString(const string& original_string, const string& delims, vector<str

void SplitString(const string& original_string, const string& delims, bool skip_empty,
vector<string>* out) {
string s(original_string);
auto s(original_string);
for (auto found = s.find_first_of(delims); found != string::npos;
s = s.substr(found + 1), found = s.find_first_of(delims)) {
if (found > 0) {
Expand All @@ -150,13 +150,11 @@ bool ends_with(const std::string& input, const std::string& match) {

/**
* Returns a string justified and padded with "bg".
*
* @param s The text to justify
* @param length the length of the text
* @param bg the character to use as the background
* @param just_type one of the following:
* LEFT
* RIGHT
* @return the justified text.
* @param just_type one of the following: LEFT, RIGHT
*/
void StringJustify(string* s, int length, char bg, JustificationType just_type) {
if (ssize(*s) > length) {
Expand Down Expand Up @@ -184,8 +182,8 @@ void StringJustify(string* s, int length, char bg, JustificationType just_type)

/**
* Removes spaces from the beginning and the end of the string s.
*
* @param str the string from which to remove spaces
* @return str with spaces removed.
*/
void StringTrim(char* str) {
string s(str);
Expand All @@ -195,11 +193,11 @@ void StringTrim(char* str) {

/**
* Removes spaces from the beginning and the end of the string s.
*
* @param s the string from which to remove spaces
* @return s with spaces removed.
*/
void StringTrim(string* s) {
string::size_type pos = s->find_first_not_of(DELIMS_WHITE);
auto pos = s->find_first_not_of(DELIMS_WHITE);
s->erase(0, pos);

pos = s->find_last_not_of(DELIMS_WHITE);
Expand All @@ -208,8 +206,8 @@ void StringTrim(string* s) {

/**
* Removes CF and LF from the beginning and the end of the string s.
*
* @param s the string from which to remove spaces
* @return s with spaces removed.
*/
void StringTrimCRLF(string* s) {
auto pos = s->find_first_not_of(DELIMS_CRLF);
Expand All @@ -222,12 +220,13 @@ void StringTrimCRLF(string* s) {
/**
* Removes spaces from the beginning and the end of the string s and
* returns it as a new string
*
* @param orig the string from which to remove spaces
* @return orig with spaces removed.
*/
string StringTrim(const string& orig) {
string s(orig);
string::size_type pos = s.find_first_not_of(DELIMS_WHITE);
auto s(orig);
auto pos = s.find_first_not_of(DELIMS_WHITE);
s.erase(0, pos);

pos = s.find_last_not_of(DELIMS_WHITE);
Expand Down Expand Up @@ -375,7 +374,17 @@ static bool IsColorCode(char c) {
if (!c) {
return false;
}
return (c == '#' || isdigit(c));
return c == '#' || isdigit(c);
}

bool wwiv::strings::contains(const std::string& haystack, const std::string_view& needle) noexcept {
try {
return haystack.find(needle) != std::string::npos;
} catch (...) {
DLOG(FATAL) << "Caught exeption in wwiv::strings::contains: '"
<< haystack << "' : '" << needle << "'";
return false;
}
}

char* stripcolors(const char* str) {
Expand Down Expand Up @@ -461,6 +470,7 @@ unsigned char upcase(unsigned char ch) {
* @return The lowercase version of the character
*/
unsigned char locase(unsigned char ch) {
// ReSharper disable once CppCStyleCast
auto* ss = (unsigned char*)strchr((const char*)translate_letters[1], ch);
if (ss) {
ch = translate_letters[0][ss - translate_letters[1]];
Expand Down Expand Up @@ -531,15 +541,6 @@ char *strupr(char *s) {
return s;
}

/** Converts string to lowercase */
char *strlwr(char *s) {
for (int i = 0; s[i] != 0; i++) {
s[i] = wwiv::strings::to_lower_case(s[i]);
}

return s;
}

// Reverses a string
char *strrev(char *s) {
CHECK(s != nullptr);
Expand Down
73 changes: 39 additions & 34 deletions core/strings.h
Expand Up @@ -16,8 +16,8 @@
/* language governing permissions and limitations under the License. */
/* */
/**************************************************************************/
#ifndef __INCLUDED_STRINGS_H__
#define __INCLUDED_STRINGS_H__
#ifndef INCLUDED_CORE_STRINGS_H
#define INCLUDED_CORE_STRINGS_H

// ReSharper disable once CppUnusedIncludeDirective
#include <cstring> // strncpy
Expand All @@ -34,8 +34,7 @@
#undef StrCat
#endif // StrCat

namespace wwiv {
namespace strings {
namespace wwiv::strings {

enum class JustificationType { LEFT, RIGHT };

Expand Down Expand Up @@ -86,80 +85,80 @@ template <typename A, typename... Args> std::string StrCat(const A& a, const Arg
}

// Comparisons
bool IsEquals(const char* str1, const char* str2);
bool iequals(const char* str1, const char* str2);
bool iequals(const std::string& s1, const std::string& s2);
int StringCompareIgnoreCase(const char* str1, const char* str2);
int StringCompare(const char* str1, const char* str2);
[[nodiscard]] bool IsEquals(const char* str1, const char* str2);
[[nodiscard]] bool iequals(const char* str1, const char* str2);
[[nodiscard]] bool iequals(const std::string& s1, const std::string& s2);
[[nodiscard]] int StringCompareIgnoreCase(const char* str1, const char* str2);
[[nodiscard]] int StringCompare(const char* str1, const char* str2);

const std::string& StringReplace(std::string* orig, const std::string& old_string,
const std::string& new_string);
std::vector<std::string> SplitString(const std::string& original_string,
const std::string& delims);
std::vector<std::string> SplitString(const std::string& original_string,
[[nodiscard]] std::vector<std::string> SplitString(const std::string& original_string,
const std::string& delims, bool skip_empty);
void SplitString(const std::string& original_string, const std::string& delims,
std::vector<std::string>* out);
void SplitString(const std::string& original_string, const std::string& delims, bool skip_empty,
std::vector<std::string>* out);

bool starts_with(const std::string& input, const std::string& match);
bool ends_with(const std::string& input, const std::string& match);
[[nodiscard]] bool starts_with(const std::string& input, const std::string& match);
[[nodiscard]] bool ends_with(const std::string& input, const std::string& match);

void StringJustify(std::string* s, int length, char bg,
JustificationType just_type);
void StringTrim(char* str);
void StringTrim(std::string* s);
std::string StringTrim(const std::string& orig);
[[nodiscard]] std::string StringTrim(const std::string& orig);

void StringTrimCRLF(std::string* s);
void StringTrimEnd(std::string* s);
void StringTrimEnd(char* str);
void StringTrimBegin(std::string* s);
void StringUpperCase(std::string* s);
std::string ToStringUpperCase(const std::string& s);
[[nodiscard]] std::string ToStringUpperCase(const std::string& s);
void StringLowerCase(std::string* s);
std::string ToStringLowerCase(const std::string& s);
[[nodiscard]] std::string ToStringLowerCase(const std::string& s);

// Strips the string from the first occurence of ch
// Strips the string from the first occurrence of ch
// Doesn't seem to be used anywhere. Maybe it should be removed.
char* StringRemoveChar(const char* str, char ch);

/**
* Joints the strings in lines, using end_of_line in between each line.
*/
std::string JoinStrings(const std::vector<std::string>& lines, const std::string& end_of_line);
[[nodiscard]] std::string JoinStrings(const std::vector<std::string>& lines, const std::string& end_of_line);

// String length without colors
int size_without_colors(const std::string& s);
[[nodiscard]] int size_without_colors(const std::string& s);

/** returns a copy of orig trimmed to size, excluding colors. */
std::string trim_to_size_ignore_colors(const std::string& orig, int size);
[[nodiscard]] std::string trim_to_size_ignore_colors(const std::string& orig, int size);

/**
* Returns orig padded to size, excluding color codes.
*/
std::string pad_to_ignore_colors(const std::string& orig, int size);
[[nodiscard]] std::string pad_to_ignore_colors(const std::string& orig, int size);

// String length
std::string::size_type size(const std::string& s);
[[nodiscard]] std::string::size_type size(const std::string& s);

// String length
std::string::size_type size(const char* s);
[[nodiscard]] std::string::size_type size(const char* s);

// String length as an int
int ssize(const char* s);
[[nodiscard]] int ssize(const char* s);

// String length as an int
int ssize(const unsigned char* s);
[[nodiscard]] int ssize(const unsigned char* s);

// String length as an int
int ssize(const std::string& s);
[[nodiscard]] int ssize(const std::string& s);

/** returns a copy of orig trimmed to size, excluding colors. */
std::string trim_to_size(const std::string& orig, int size);

/** Typesafe version of toupper */
/** Type-safe version of toupper */
template<class T, typename = std::enable_if_t<std::is_convertible_v<T, char>, char>>
T to_upper_case(const T a) { return static_cast<T>(::toupper(a)); }

Expand Down Expand Up @@ -204,23 +203,30 @@ template <typename A, typename... Args> std::string StrCat(const A& a, const Arg
s, b);
}

} // namespace strings
/**
* Return true if haystack contains needed as a substring.
*
* Like boost::contains.
* See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1679r3.html
* for proposal to add as std::string::contains.
*/
bool contains(const std::string& haystack, const std::string_view& needle) noexcept;

} // namespace wwiv

// Function Prototypes
char* stripcolors(const char* pszOrig);
std::string stripcolors(const std::string& orig);
unsigned char upcase(unsigned char ch);
unsigned char locase(unsigned char ch);
[[nodiscard]] char* stripcolors(const char* pszOrig);
[[nodiscard]] std::string stripcolors(const std::string& orig);
[[nodiscard]] unsigned char upcase(unsigned char ch);
[[nodiscard]] unsigned char locase(unsigned char ch);

void properize(char* text);
std::string properize(const std::string& text);
[[nodiscard]] std::string properize(const std::string& text);

extern const char* DELIMS_WHITE;

/** returns true if needle is found in haystack ,ignoring case */
bool ifind_first(const std::string& haystack, const std::string& needle);
[[nodiscard]] bool ifind_first(const std::string& haystack, const std::string& needle);

#ifdef _WIN32

Expand All @@ -231,7 +237,6 @@ template <typename A, typename... Args> std::string StrCat(const A& a, const Arg

#else // _WIN32
char* strupr(char* s);
char* strlwr(char* s);
char* strrev(char* s);

#endif // _WIN32
Expand Down

0 comments on commit 7cf31cd

Please sign in to comment.