Closed ErikSchierboom closed 8 years ago
MailAddress is in System.dll so it would represent no additional dependencies for FsCheck so I don't see why not.
Okay, great! I'll have a go at it then.
I'm working on adding this feature, but I have one important question: email addresses have quite a complex format. Should I create a generator that can randomly generate every type of valid email address? If so, the generator will probably be quite complex.
If not, should I only generate "simple" email addresses, or should I use a list of pre-defined email addresses which contains all edge cases? That list could look something like this:
What would you consider to be the best approach?
The "usual" approach is to have a (relatively) general generator, augmented with special cases that have a high probability of being generated. Have a look at Arb.Default.Float as an example: it generates floats, but with a high chance of hitting epsilon, min value etc.
Does that make sense?
Yes it does. Any preferences to how the general generator should work? More specifically, should I generate random strings (of the correct length and using the correct characters of course), or use a pre-defined set of values? People don't expect an email address to look like "a2#$*/e@example.com" or something like that, although that is of what FsCheck can help you with, testing every valid email address.
I would pick totally random strings (as long as they can give a valid email address). It's easier for users to filter out cases they don't want than to add them after the fact.
As a an experienced programmer, I'd like a MailAddress generator to seek out as many exotic values as possible. You may want to consider the following, however:
If the target is to generate MailAddress
values, you may need to constrain the generated values to those that MailAddress
considers valid. It wouldn't surprise me if there are strings that are considered valid according to whatever specification defines SMTP addresses, but that MailAddress
doesn't accept.
On the other hand, if that's the case, then .NET is open source too, as well :wink:
The other issue worth considering is that some generated email addresses may represent real addresses.
When FsCheck is used against pure functions, that isn't an issue, but if someone ever decides to use FsCheck for integration testing, a side effect could be that email are sent to real mail boxes.
If that ever happens, if someone wants to place the blame, the only reasonable target for the blame ought to be the developer who chose to use FsCheck against code that sends email. Still, some people aren't reasonable, particularly when their ass is on the line, so we could hypothetically risk that someone tries to blame FsCheck.
I still think we should generate addresses according to all sorts of edge cases, but I think at least we should put a warning in the documentation to the effect that it may generate real addresses, and that it's the users' responsibility if emails are sent to real mail boxes as a result of running tests.
That was one of my worries so, which I was planning to generate random strings only for the local part of the email address, and use the following reserved second-level domains for the host:
I could also use the top-level domain .test
, which also has been reserved for this purpose.
This approach would prevent any accidental emails being sent of to real people. The only disadvantage is that the host name is not really random, although I could add a random subdomain to the .test
top-level domain.
I think it'd be more in line with property-based testing to attempt to generate as wide a range of valid values as possible. I know we had this discussion when we added support for MailAddress
to AutoFixture, but I consider FsCheck a sharper tool than AutoFixture.
The purpose of AutoFixture is to fill objects with values that are as likely to be valid as possible.
The purpose of property-based testing, on the other hand, is to generate values that are as varied as possible, in order to explore edge cases of systems.
Limiting the host part to only example.com|net|org
doesn't, IMO, fit that purpose.
Assuming we go for the random domain names, there is a part of the domain name that is not random, namely the top level domain (see http://data.iana.org/TLD/tlds-alpha-by-domain.txt). I assume I should be using the exhaustive list in the generation process. However, this is quite a long list, is that okay? It would look like this in code:
let topLevelDomain =
[|
"aaa";
"aarp";
"abb";
"abbott";
"abbvie";
"abogado";
"abudhabi";
"ac";
"academy";
"accenture";
"accountant";
"accountants";
"aco";
"active";
"actor";
"ad";
"adac";
"ads";
"adult";
"ae";
"aeg";
"aero";
"af";
"afl";
"ag";
"agakhan";
"agency";
"ai";
"aig";
"airforce";
"airtel";
"akdn";
"al";
"alibaba";
"alipay";
"allfinanz";
"ally";
"alsace";
"am";
"amica";
"amsterdam";
"analytics";
"android";
"anquan";
"ao";
"apartments";
"app";
"apple";
"aq";
"aquarelle";
"ar";
"aramco";
"archi";
"army";
"arpa";
"arte";
"as";
"asia";
"associates";
"at";
"attorney";
"au";
"auction";
"audi";
"audio";
"author";
"auto";
"autos";
"avianca";
"aw";
"aws";
"ax";
"axa";
"az";
"azure";
"ba";
"baby";
"baidu";
"band";
"bank";
"bar";
"barcelona";
"barclaycard";
"barclays";
"barefoot";
"bargains";
"bauhaus";
"bayern";
"bb";
"bbc";
"bbva";
"bcg";
"bcn";
"bd";
"be";
"beats";
"beer";
"bentley";
"berlin";
"best";
"bet";
"bf";
"bg";
"bh";
"bharti";
"bi";
"bible";
"bid";
"bike";
"bing";
"bingo";
"bio";
"biz";
"bj";
"black";
"blackfriday";
"bloomberg";
"blue";
"bm";
"bms";
"bmw";
"bn";
"bnl";
"bnpparibas";
"bo";
"boats";
"boehringer";
"bom";
"bond";
"boo";
"book";
"boots";
"bosch";
"bostik";
"bot";
"boutique";
"br";
"bradesco";
"bridgestone";
"broadway";
"broker";
"brother";
"brussels";
"bs";
"bt";
"budapest";
"bugatti";
"build";
"builders";
"business";
"buy";
"buzz";
"bv";
"bw";
"by";
"bz";
"bzh";
"ca";
"cab";
"cafe";
"cal";
"call";
"camera";
"camp";
"cancerresearch";
"canon";
"capetown";
"capital";
"car";
"caravan";
"cards";
"care";
"career";
"careers";
"cars";
"cartier";
"casa";
"cash";
"casino";
"cat";
"catering";
"cba";
"cbn";
"cc";
"cd";
"ceb";
"center";
"ceo";
"cern";
"cf";
"cfa";
"cfd";
"cg";
"ch";
"chanel";
"channel";
"chase";
"chat";
"cheap";
"chloe";
"christmas";
"chrome";
"church";
"ci";
"cipriani";
"circle";
"cisco";
"citic";
"city";
"cityeats";
"ck";
"cl";
"claims";
"cleaning";
"click";
"clinic";
"clinique";
"clothing";
"cloud";
"club";
"clubmed";
"cm";
"cn";
"co";
"coach";
"codes";
"coffee";
"college";
"cologne";
"com";
"commbank";
"community";
"company";
"compare";
"computer";
"comsec";
"condos";
"construction";
"consulting";
"contact";
"contractors";
"cooking";
"cool";
"coop";
"corsica";
"country";
"coupon";
"coupons";
"courses";
"cr";
"credit";
"creditcard";
"creditunion";
"cricket";
"crown";
"crs";
"cruises";
"csc";
"cu";
"cuisinella";
"cv";
"cw";
"cx";
"cy";
"cymru";
"cyou";
"cz";
"dabur";
"dad";
"dance";
"date";
"dating";
"datsun";
"day";
"dclk";
"dds";
"de";
"dealer";
"deals";
"degree";
"delivery";
"dell";
"deloitte";
"delta";
"democrat";
"dental";
"dentist";
"desi";
"design";
"dev";
"diamonds";
"diet";
"digital";
"direct";
"directory";
"discount";
"dj";
"dk";
"dm";
"dnp";
"do";
"docs";
"dog";
"doha";
"domains";
"download";
"drive";
"dubai";
"durban";
"dvag";
"dz";
"earth";
"eat";
"ec";
"edeka";
"edu";
"education";
"ee";
"eg";
"email";
"emerck";
"energy";
"engineer";
"engineering";
"enterprises";
"epson";
"equipment";
"er";
"erni";
"es";
"esq";
"estate";
"et";
"eu";
"eurovision";
"eus";
"events";
"everbank";
"exchange";
"expert";
"exposed";
"express";
"extraspace";
"fage";
"fail";
"fairwinds";
"faith";
"family";
"fan";
"fans";
"farm";
"fashion";
"fast";
"feedback";
"ferrero";
"fi";
"film";
"final";
"finance";
"financial";
"firestone";
"firmdale";
"fish";
"fishing";
"fit";
"fitness";
"fj";
"fk";
"flickr";
"flights";
"flir";
"florist";
"flowers";
"flsmidth";
"fly";
"fm";
"fo";
"foo";
"football";
"ford";
"forex";
"forsale";
"forum";
"foundation";
"fox";
"fr";
"fresenius";
"frl";
"frogans";
"frontier";
"ftr";
"fund";
"furniture";
"futbol";
"fyi";
"ga";
"gal";
"gallery";
"gallo";
"gallup";
"game";
"garden";
"gb";
"gbiz";
"gd";
"gdn";
"ge";
"gea";
"gent";
"genting";
"gf";
"gg";
"ggee";
"gh";
"gi";
"gift";
"gifts";
"gives";
"giving";
"gl";
"glass";
"gle";
"global";
"globo";
"gm";
"gmail";
"gmbh";
"gmo";
"gmx";
"gn";
"gold";
"goldpoint";
"golf";
"goo";
"goog";
"google";
"gop";
"got";
"gov";
"gp";
"gq";
"gr";
"grainger";
"graphics";
"gratis";
"green";
"gripe";
"group";
"gs";
"gt";
"gu";
"guardian";
"gucci";
"guge";
"guide";
"guitars";
"guru";
"gw";
"gy";
"hamburg";
"hangout";
"haus";
"hdfcbank";
"health";
"healthcare";
"help";
"helsinki";
"here";
"hermes";
"hiphop";
"hitachi";
"hiv";
"hk";
"hkt";
"hm";
"hn";
"hockey";
"holdings";
"holiday";
"homedepot";
"homes";
"honda";
"horse";
"host";
"hosting";
"hoteles";
"hotmail";
"house";
"how";
"hr";
"hsbc";
"ht";
"htc";
"hu";
"hyundai";
"ibm";
"icbc";
"ice";
"icu";
"id";
"ie";
"ifm";
"iinet";
"il";
"im";
"imamat";
"immo";
"immobilien";
"in";
"industries";
"infiniti";
"info";
"ing";
"ink";
"institute";
"insurance";
"insure";
"int";
"international";
"investments";
"io";
"ipiranga";
"iq";
"ir";
"irish";
"is";
"iselect";
"ismaili";
"ist";
"istanbul";
"it";
"itau";
"iwc";
"jaguar";
"java";
"jcb";
"jcp";
"je";
"jetzt";
"jewelry";
"jlc";
"jll";
"jm";
"jmp";
"jnj";
"jo";
"jobs";
"joburg";
"jot";
"joy";
"jp";
"jpmorgan";
"jprs";
"juegos";
"kaufen";
"kddi";
"ke";
"kerryhotels";
"kerrylogistics";
"kerryproperties";
"kfh";
"kg";
"kh";
"ki";
"kia";
"kim";
"kinder";
"kitchen";
"kiwi";
"km";
"kn";
"koeln";
"komatsu";
"kp";
"kpmg";
"kpn";
"kr";
"krd";
"kred";
"kuokgroup";
"kw";
"ky";
"kyoto";
"kz";
"la";
"lacaixa";
"lamborghini";
"lamer";
"lancaster";
"land";
"landrover";
"lanxess";
"lasalle";
"lat";
"latrobe";
"law";
"lawyer";
"lb";
"lc";
"lds";
"lease";
"leclerc";
"legal";
"lexus";
"lgbt";
"li";
"liaison";
"lidl";
"life";
"lifeinsurance";
"lifestyle";
"lighting";
"like";
"limited";
"limo";
"lincoln";
"linde";
"link";
"lipsy";
"live";
"living";
"lixil";
"lk";
"loan";
"loans";
"locus";
"lol";
"london";
"lotte";
"lotto";
"love";
"lr";
"ls";
"lt";
"ltd";
"ltda";
"lu";
"lupin";
"luxe";
"luxury";
"lv";
"ly";
"ma";
"madrid";
"maif";
"maison";
"makeup";
"man";
"management";
"mango";
"market";
"marketing";
"markets";
"marriott";
"mba";
"mc";
"md";
"me";
"med";
"media";
"meet";
"melbourne";
"meme";
"memorial";
"men";
"menu";
"meo";
"metlife";
"mg";
"mh";
"miami";
"microsoft";
"mil";
"mini";
"mk";
"ml";
"mls";
"mm";
"mma";
"mn";
"mo";
"mobi";
"mobily";
"moda";
"moe";
"moi";
"mom";
"monash";
"money";
"montblanc";
"mormon";
"mortgage";
"moscow";
"motorcycles";
"mov";
"movie";
"movistar";
"mp";
"mq";
"mr";
"ms";
"mt";
"mtn";
"mtpc";
"mtr";
"mu";
"museum";
"mutual";
"mutuelle";
"mv";
"mw";
"mx";
"my";
"mz";
"na";
"nadex";
"nagoya";
"name";
"natura";
"navy";
"nc";
"ne";
"nec";
"net";
"netbank";
"network";
"neustar";
"new";
"news";
"next";
"nextdirect";
"nexus";
"nf";
"ng";
"ngo";
"nhk";
"ni";
"nico";
"nikon";
"ninja";
"nissan";
"nissay";
"nl";
"no";
"nokia";
"northwesternmutual";
"norton";
"nowruz";
"nowtv";
"np";
"nr";
"nra";
"nrw";
"ntt";
"nu";
"nyc";
"nz";
"obi";
"office";
"okinawa";
"olayan";
"olayangroup";
"om";
"omega";
"one";
"ong";
"onl";
"online";
"ooo";
"oracle";
"orange";
"org";
"organic";
"origins";
"osaka";
"otsuka";
"ovh";
"pa";
"page";
"pamperedchef";
"panerai";
"paris";
"pars";
"partners";
"parts";
"party";
"passagens";
"pccw";
"pe";
"pet";
"pf";
"pg";
"ph";
"pharmacy";
"philips";
"photo";
"photography";
"photos";
"physio";
"piaget";
"pics";
"pictet";
"pictures";
"pid";
"pin";
"ping";
"pink";
"pizza";
"pk";
"pl";
"place";
"play";
"playstation";
"plumbing";
"plus";
"pm";
"pn";
"pohl";
"poker";
"porn";
"post";
"pr";
"praxi";
"press";
"pro";
"prod";
"productions";
"prof";
"progressive";
"promo";
"properties";
"property";
"protection";
"ps";
"pt";
"pub";
"pw";
"pwc";
"py";
"qa";
"qpon";
"quebec";
"quest";
"racing";
"re";
"read";
"realtor";
"realty";
"recipes";
"red";
"redstone";
"redumbrella";
"rehab";
"reise";
"reisen";
"reit";
"ren";
"rent";
"rentals";
"repair";
"report";
"republican";
"rest";
"restaurant";
"review";
"reviews";
"rexroth";
"rich";
"richardli";
"ricoh";
"rio";
"rip";
"ro";
"rocher";
"rocks";
"rodeo";
"room";
"rs";
"rsvp";
"ru";
"ruhr";
"run";
"rw";
"rwe";
"ryukyu";
"sa";
"saarland";
"safe";
"safety";
"sakura";
"sale";
"salon";
"samsung";
"sandvik";
"sandvikcoromant";
"sanofi";
"sap";
"sapo";
"sarl";
"sas";
"saxo";
"sb";
"sbi";
"sbs";
"sc";
"sca";
"scb";
"schaeffler";
"schmidt";
"scholarships";
"school";
"schule";
"schwarz";
"science";
"scor";
"scot";
"sd";
"se";
"seat";
"security";
"seek";
"select";
"sener";
"services";
"seven";
"sew";
"sex";
"sexy";
"sfr";
"sg";
"sh";
"sharp";
"shaw";
"shell";
"shia";
"shiksha";
"shoes";
"shouji";
"show";
"shriram";
"si";
"sina";
"singles";
"site";
"sj";
"sk";
"ski";
"skin";
"sky";
"skype";
"sl";
"sm";
"smile";
"sn";
"sncf";
"so";
"soccer";
"social";
"softbank";
"software";
"sohu";
"solar";
"solutions";
"song";
"sony";
"soy";
"space";
"spiegel";
"spot";
"spreadbetting";
"sr";
"srl";
"st";
"stada";
"star";
"starhub";
"statebank";
"statefarm";
"statoil";
"stc";
"stcgroup";
"stockholm";
"storage";
"store";
"stream";
"studio";
"study";
"style";
"su";
"sucks";
"supplies";
"supply";
"support";
"surf";
"surgery";
"suzuki";
"sv";
"swatch";
"swiss";
"sx";
"sy";
"sydney";
"symantec";
"systems";
"sz";
"tab";
"taipei";
"talk";
"taobao";
"tatamotors";
"tatar";
"tattoo";
"tax";
"taxi";
"tc";
"tci";
"td";
"team";
"tech";
"technology";
"tel";
"telecity";
"telefonica";
"temasek";
"tennis";
"teva";
"tf";
"tg";
"th";
"thd";
"theater";
"theatre";
"tickets";
"tienda";
"tiffany";
"tips";
"tires";
"tirol";
"tj";
"tk";
"tl";
"tm";
"tmall";
"tn";
"to";
"today";
"tokyo";
"tools";
"top";
"toray";
"toshiba";
"total";
"tours";
"town";
"toyota";
"toys";
"tr";
"trade";
"trading";
"training";
"travel";
"travelers";
"travelersinsurance";
"trust";
"trv";
"tt";
"tube";
"tui";
"tunes";
"tushu";
"tv";
"tvs";
"tw";
"tz";
"ua";
"ubs";
"ug";
"uk";
"unicom";
"university";
"uno";
"uol";
"us";
"uy";
"uz";
"va";
"vacations";
"vana";
"vc";
"ve";
"vegas";
"ventures";
"verisign";
"versicherung";
"vet";
"vg";
"vi";
"viajes";
"video";
"vig";
"viking";
"villas";
"vin";
"vip";
"virgin";
"vision";
"vista";
"vistaprint";
"viva";
"vlaanderen";
"vn";
"vodka";
"volkswagen";
"vote";
"voting";
"voto";
"voyage";
"vu";
"vuelos";
"wales";
"walter";
"wang";
"wanggou";
"warman";
"watch";
"watches";
"weather";
"weatherchannel";
"webcam";
"weber";
"website";
"wed";
"wedding";
"weibo";
"weir";
"wf";
"whoswho";
"wien";
"wiki";
"williamhill";
"win";
"windows";
"wine";
"wme";
"wolterskluwer";
"work";
"works";
"world";
"ws";
"wtc";
"wtf";
"xbox";
"xerox";
"xihuan";
"xin";
"xn--11b4c3d";
"xn--1ck2e1b";
"xn--1qqw23a";
"xn--30rr7y";
"xn--3bst00m";
"xn--3ds443g";
"xn--3e0b707e";
"xn--3pxu8k";
"xn--42c2d9a";
"xn--45brj9c";
"xn--45q11c";
"xn--4gbrim";
"xn--55qw42g";
"xn--55qx5d";
"xn--5tzm5g";
"xn--6frz82g";
"xn--6qq986b3xl";
"xn--80adxhks";
"xn--80ao21a";
"xn--80asehdb";
"xn--80aswg";
"xn--8y0a063a";
"xn--90a3ac";
"xn--90ais";
"xn--9dbq2a";
"xn--9et52u";
"xn--9krt00a";
"xn--b4w605ferd";
"xn--bck1b9a5dre4c";
"xn--c1avg";
"xn--c2br7g";
"xn--cck2b3b";
"xn--cg4bki";
"xn--clchc0ea0b2g2a9gcd";
"xn--czr694b";
"xn--czrs0t";
"xn--czru2d";
"xn--d1acj3b";
"xn--d1alf";
"xn--e1a4c";
"xn--eckvdtc9d";
"xn--efvy88h";
"xn--estv75g";
"xn--fct429k";
"xn--fhbei";
"xn--fiq228c5hs";
"xn--fiq64b";
"xn--fiqs8s";
"xn--fiqz9s";
"xn--fjq720a";
"xn--flw351e";
"xn--fpcrj9c3d";
"xn--fzc2c9e2c";
"xn--fzys8d69uvgm";
"xn--g2xx48c";
"xn--gckr3f0f";
"xn--gecrj9c";
"xn--h2brj9c";
"xn--hxt814e";
"xn--i1b6b1a6a2e";
"xn--imr513n";
"xn--io0a7i";
"xn--j1aef";
"xn--j1amh";
"xn--j6w193g";
"xn--jlq61u9w7b";
"xn--jvr189m";
"xn--kcrx77d1x4a";
"xn--kprw13d";
"xn--kpry57d";
"xn--kpu716f";
"xn--kput3i";
"xn--l1acc";
"xn--lgbbat1ad8j";
"xn--mgb9awbf";
"xn--mgba3a3ejt";
"xn--mgba3a4f16a";
"xn--mgba7c0bbn0a";
"xn--mgbaam7a8h";
"xn--mgbab2bd";
"xn--mgbayh7gpa";
"xn--mgbb9fbpob";
"xn--mgbbh1a71e";
"xn--mgbc0a9azcg";
"xn--mgbca7dzdo";
"xn--mgberp4a5d4ar";
"xn--mgbpl2fh";
"xn--mgbt3dhd";
"xn--mgbtx2b";
"xn--mgbx4cd0ab";
"xn--mix891f";
"xn--mk1bu44c";
"xn--mxtq1m";
"xn--ngbc5azd";
"xn--ngbe9e0a";
"xn--node";
"xn--nqv7f";
"xn--nqv7fs00ema";
"xn--nyqy26a";
"xn--o3cw4h";
"xn--ogbpf8fl";
"xn--p1acf";
"xn--p1ai";
"xn--pbt977c";
"xn--pgbs0dh";
"xn--pssy2u";
"xn--q9jyb4c";
"xn--qcka1pmc";
"xn--qxam";
"xn--rhqv96g";
"xn--rovu88b";
"xn--s9brj9c";
"xn--ses554g";
"xn--t60b56a";
"xn--tckwe";
"xn--unup4y";
"xn--vermgensberater-ctb";
"xn--vermgensberatung-pwb";
"xn--vhquv";
"xn--vuq861b";
"xn--w4r85el8fhu5dnra";
"xn--wgbh1c";
"xn--wgbl6a";
"xn--xhq521b";
"xn--xkc2al3hye2a";
"xn--xkc2dl3a5ee0h";
"xn--y9a3aq";
"xn--yfro4i67o";
"xn--ygbi2ammx";
"xn--zfr164b";
"xperia";
"xxx";
"xyz";
"yachts";
"yahoo";
"yamaxun";
"yandex";
"ye";
"yodobashi";
"yoga";
"yokohama";
"you";
"youtube";
"yt";
"yun";
"za";
"zara";
"zero";
"zip";
"zm";
"zone";
"zuerich";
"zw"; |]
|> Gen.elements
utf-8 characters are also allowed for internationalized email addresses, so perhaps they should have their own complementary generator.
Closing as this is done (please re-open if I missed something).
Doesn't seem that this is available for netstandard 2.0, is there a reason for that?
That's probably because we only target net standard 1.6 now, which doesn't have MailAddress. I'm planning to target 2.0 specifically as per nuget recommendations in the next minor release, which should solve that (if MailAddress is in the 2.0 API surface, that is).
It would be great if FsCheck would be able to generate
MailAddress
instances. I could work on this, but first I'd like to know if this is something that you'd support.