public void SaveWriteAndRetrieveSingularValueTest() { ConfigManipulator target = new ConfigManipulator(testAppConfigPath); string currentServer = target.GetValue("Server"); target.SaveValue("Server", currentServer + "a"); target.WriteConfig(testAppConfigPath); Assert.AreEqual(target.GetValue("Server"), currentServer + "a"); }
public void TestConfigManipulator_ExpectedStateAchieved(string json, bool ConsoleRemainOpenExpectedValue, bool InteractionModeExpectedValue) { //Arrange string execeptionMessage = string.Empty; //Act ConfigManipulator configManipulator = new ConfigManipulator(configurationFilePath: string.Empty, configurationFileJson: json); //Assert Assert.IsTrue(configManipulator.ConsoleRemainOpen == ConsoleRemainOpenExpectedValue && configManipulator.InteractionMode == InteractionModeExpectedValue); }
public void GetSingularValueTest() { // pull up the config file the old fashioned way ;) XmlDocument x = new XmlDocument(); x.Load(testAppConfigPath); string currentServer = x.SelectSingleNode("configuration/appSettings/add[@key='Server']").Attributes["value"].Value; ConfigManipulator target = new ConfigManipulator(testAppConfigPath); Assert.AreEqual(currentServer, target.GetValue("Server")); }
public void SaveAndRetrieveDictionaryValueTest() { Dictionary <object, object> firstDictionary = new Dictionary <object, object> { { (int)1, "a longer string" }, { (int)2, @"a messud up string" }, { (int)3, @"a string with some icky characters! <a><&b><c;>" }, { "asdf", @"a string with some icky characters! <a><&b><<c;> " }, { false, @"true" }, { true, @"false" } }; ConfigManipulator target = new ConfigManipulator(testAppConfigPath); target.SaveValue(firstDictionary, "test1"); Dictionary <object, object> retrievedDictionary = target.GetDictionary("test1"); foreach (object o in retrievedDictionary.Keys) { object a = firstDictionary[o]; object b = retrievedDictionary[o]; Assert.AreEqual(firstDictionary[o], retrievedDictionary[o]); } Dictionary <object, object> secondDictionary = new Dictionary <object, object> { { "", "a longer string" }, { "a longer string", @"a messud up string" }, { "a string with some icky characters! <a><&b><c;>", @"a string with some icky characters! <a><&b><c;>" } }; target = new ConfigManipulator(testAppConfigPath); target.SaveValue(secondDictionary, "test2"); retrievedDictionary = target.GetDictionary("test2"); foreach (object o in retrievedDictionary.Keys) { object a = secondDictionary[o]; object b = retrievedDictionary[o]; Assert.AreEqual(secondDictionary[o], retrievedDictionary[o]); } }
public void TestConfigManipulator_InvalidConfigHandled(string json, string expextedErrorMessage) { //Arrange string execeptionMessage = string.Empty; //Act try { ConfigManipulator configManipulator = new ConfigManipulator(configurationFilePath: string.Empty, configurationFileJson: json); var monikerUriMappingDictionary = configManipulator.LoadMonikerUriMappingDictionary(); } catch (Exception ex) { execeptionMessage = ex.Message; } //Assert Assert.IsTrue(string.Compare(expextedErrorMessage, execeptionMessage) == 0); }
static async Task Main(string[] args) { //Http client will be used due provided simplified interface to make async requests HttpClient httpClient = new HttpClient(); //Will store webscraping process instances List <Task> scrapingExecutions = new List <Task>(); const string errorMessagePrefix = "Issue During Execution:"; //Used to decide if the console should remain open post execution bool consoleRemainOpen = false; string input = default; try { Console.WriteLine($"Start Of Application Execution: {DateTime.Now}"); //ToDo - Ensure a default configuration file is created in the required directory if it is not present //The configuration manipulator that will interact with the configuration file ConfigManipulator configManipulator = new ConfigManipulator(configurationFilePath: $@"{Directory.GetCurrentDirectory()}\{AppSettings.Default.ConfigFilePath}"); //A mapping that associates a moniker, uri and the webscraper type that should be used Dictionary <string, (string Uri, ScraperType ScraperType)> monikerUriMapping = configManipulator.LoadMonikerUriMappingDictionary(); //If arguments have been provided via the command line convert them to a string if (args.Length >= 1) { input = string.Join(Separators.SpaceSeparator, args); } //Load additional options provided by the configuration file bool interactionMode = configManipulator.InteractionMode; consoleRemainOpen = configManipulator.ConsoleRemainOpen; //Instantiate user input processor to ensure input is valid UserInputProcessor userInputProcessor = new UserInputProcessor(); //Will run at least once or continuously if interaction mode is true for (int i = 0; i < 1 || interactionMode; i++) { try { //Only read from the console if no CLI arguments have been provided if (string.IsNullOrEmpty(input)) { Console.WriteLine("Enter Argument:"); input = Console.ReadLine(); } //Validate and process input userInputProcessor.ProcessInput(input); //ToDo-- trigger cancellation token if it is able to be canceled to signal tasks instances they should stop //Break out of the loop if the exit command has been input if (userInputProcessor.Exit) { break; } //Throw an exception if the input is not valid if (!userInputProcessor.IsUserInputValid) { throw new Exception($"Ensure Input Is Valid: {input}"); } //Start a new scraping execution task instance if the input is valid scrapingExecutions.Add(Task.Run(async() => { try { //Ensures the moniker argument is valid e.g hackernews if (!monikerUriMapping.Keys.Contains(userInputProcessor.MonikerArgument)) { throw new Exception("Moniker Not Found In The Config Files Moniker Uri Mapping Property"); } //ToDo - only continue main process loop once the trailing arguments has been stored locally before userInputProcessor state reset Dictionary <string, string> trailingArguments = userInputProcessor.TrailingArguments; //Collect its associated uri to provide the webscraper string uri = monikerUriMapping[userInputProcessor.MonikerArgument].Uri; //Select the associated scraper type that should be used with the valid moniker argument switch (monikerUriMapping[userInputProcessor.MonikerArgument].ScraperType) { case ScraperType.HackerNewsScraper: //Initialize algorithm based on selected mapping item IWebScraper webScraper = ScraperFactory.CreateWebScraperInstance(ScraperType.HackerNewsScraper); await webScraper.ExecuteScraping(uri, httpClient, trailingArguments); break; default: //Will throw an exception if the associated web scraper is unidentified throw new Exception("Provided Web Scraper Is Unidentified"); } } catch (Exception ex) { //Display error information based on web scrapping execution errors //Log Error Message Console.WriteLine($"Issue During {userInputProcessor.MonikerArgument} Process: {ex.Message}"); } })); } catch (Exception ex) { //Ensures application can continue when running in interaction mode //If application was extended to run a collection of inputs, ensures collection items can be enumerated if errors occurs during process Console.WriteLine($"{errorMessagePrefix} {ex.Message}"); } //Clear input input = string.Empty; } } catch (Exception ex) { //Display error message that caused main execution to stop Console.WriteLine($"{errorMessagePrefix} {ex.Message}"); } finally { //Wait for scraping executions to complete if (scrapingExecutions.Count() >= 1) { await Task.WhenAll(scrapingExecutions); } httpClient.Dispose(); } Console.WriteLine($"End Of Application Execution: {DateTime.Now}"); //Temp Will Allow The Viewing Of The Results if (consoleRemainOpen) { Console.ReadLine(); } }