none
이번에 오픈소스로 공개된 계산기 엡에 관한 질문입니다.

    질문

  • 안녕하세요.

    이번에 오픈소스로 공개된 계산기 앱의 소스를 다운받아 VS2017에서 열어봤는데, 다음과 같은 에러메시지를 뱉더군요.

    1>------ 빌드 시작: 프로젝트: CalcViewModel, 구성: Debug Win32 ------
    1>CopyPasteManager.cpp
    1>c:\users\c0001\source\repos\calculator-master\calculator-master\src\calcviewmodel\common\copypastemanager.cpp(1): error C2220: 경고가 오류로 처리되어 생성된 'object' 파일이 없습니다.
    1>c:\users\c0001\source\repos\calculator-master\calculator-master\src\calcviewmodel\common\copypastemanager.cpp(1): warning C4819: 현재 코드 페이지(949)에서 표시할 수 없는 문자가 파일에 들어 있습니다. 데이터가 손실되지 않게 하려면 해당 파일을 유니코드 형식으로 저장하십시오.
    1>"CalcViewModel.vcxproj" 프로젝트를 빌드했습니다. - 실패
    2>------ 빌드 시작: 프로젝트: Calculator, 구성: Debug Win32 ------
    3>------ 빌드 시작: 프로젝트: CalculatorUnitTests, 구성: Debug Win32 ------
    3>CopyPasteManagerTest.cpp
    3>CurrencyConverterUnitTests.cpp
    3>c:\users\c0001\source\repos\calculator-master\calculator-master\src\calculatorunittests\copypastemanagertest.cpp(1): error C2220: 경고가 오류로 처리되어 생성된 'object' 파일이 없습니다.
    3>c:\users\c0001\source\repos\calculator-master\calculator-master\src\calculatorunittests\copypastemanagertest.cpp(1): warning C4819: 현재 코드 페이지(949)에서 표시할 수 없는 문자가 파일에 들어 있습니다. 데이터가 손실되지 않게 하려면 해당 파일을 유니코드 형식으로 저장하십시오.
    3>c:\users\c0001\source\repos\calculator-master\calculator-master\src\calculatorunittests\currencyconverterunittests.cpp(1): error C2220: 경고가 오류로 처리되어 생성된 'object' 파일이 없습니다.
    3>c:\users\c0001\source\repos\calculator-master\calculator-master\src\calculatorunittests\currencyconverterunittests.cpp(1): warning C4819: 현재 코드 페이지(949)에서 표시할 수 없는 문자가 파일에 들어 있습니다. 데이터가 손실되지 않게 하려면 해당 파일을 유니코드 형식으로 저장하십시오.
    3>c:\users\c0001\source\repos\calculator-master\calculator-master\src\calculatorunittests\currencyconverterunittests.cpp(92): fatal error C1075: '{': 일치하는 토큰을 찾을 수 없습니다.
    3>"CalculatorUnitTests.vcxproj" 프로젝트를 빌드했습니다. - 실패
    2>LINK : fatal error LNK1181: 'C:\Users\c0001\source\repos\calculator-master\calculator-master\src\Debug\CalcViewModel\CalcViewModel.lib' 입력 파일을 열 수 없습니다.
    2>"Calculator.vcxproj" 프로젝트를 빌드했습니다. - 실패
    ========== 빌드: 성공 0, 실패 3, 최신 1, 생략 0 ==========
    
     

    깃헙에서 지시한대로 xaml styler도 설치를 한 다음 소스를 열고 빌드를 했는데, 계속 위와 같은 실패메시지만 나옵니다.

    어찌해야 할런지 조언 부탁드립니다.

    2019년 4월 3일 수요일 오후 10:33

답변

모든 응답

  • 이런 경우, 일단 프로젝트 설정 창에 가서 "Treat Warnings As Errors" 기능을 끄세요.

    그렇게 하면 위의 오류 중에서 마지막 것을 제외하면 컴파일이 될 것입니다. 문제는 마지막 92 라인에 있는 것인데요. 아마도 그 파일을 열어 보면 거기에 영어도, 한글도 아닌 깨진 문자열이 들어 있을 것입니다. 그 문자열과 함께 "{" 코드가 있는 것이 합쳐지면서 오류가 나는 경우일텐데요. 이런 경우에는 그 부분의 깨진 문자열을 적절히 삭제하고 저장 후에 컴파일하면 됩니다.

    참고로, 원문 그대로 살리고 싶다면 저 파일을 만든 당시의 로케일 값을 알아내야 합니다. 그다음, 그 로케일을 지원하도록 윈도우의 국가 설정을 바꾸면 (이후 한글은 안 되겠지만) 정상적으로 파일은 볼 수 있을 것입니다. 그 상태에서 해당 cpp 파일을 UTF-8 등의 인코딩으로 저장한 후 다시 윈도우의 국가 설정을 원복해서 한글 환경으로 돌아오면 됩니다.

    물론 후자의 방법으로 하느니, 그냥 적절하게 에러가 발생하지 않도록 깨진 문자열만 제거해주는 것이 더 편합니다.

    2019년 4월 4일 목요일 오전 1:18
  • 님이 말씀하신대로 "treat warnings as errors" 기능을 끄고 나서 다시 빌드를 해 보니 

    1>------ 빌드 시작: 프로젝트: CalculatorUnitTests, 구성: Debug Win32 ------
    1>CurrencyConverterUnitTests.cpp
    1>c:\users\c0001\source\repos\calculator-master\calculator-master\src\calculatorunittests\currencyconverterunittests.cpp(1): warning C4819: 현재 코드 페이지(949)에서 표시할 수 없는 문자가 파일에 들어 있습니다. 데이터가 손실되지 않게 하려면 해당 파일을 유니코드 형식으로 저장하십시오.
    1>c:\users\c0001\source\repos\calculator-master\calculator-master\src\calculatorunittests\currencyconverterunittests.cpp(92): fatal error C1075: '{': 일치하는 토큰을 찾을 수 없습니다.
    1>"CalculatorUnitTests.vcxproj" 프로젝트를 빌드했습니다. - 실패
    ========== 빌드: 성공 0, 실패 1, 최신 3, 생략 0 ==========

    위와 같이 메시지가 뜨는데, 표시할 수 없는 문자를 도대체 못 찾겠네요.  소스코드는 

    // Copyright (c) Microsoft Corporation. All rights reserved.
    // Licensed under the MIT License.
    
    #include "pch.h"
    #include <CppUnitTest.h>
    
    #include "CalcViewModel/DataLoaders/CurrencyDataLoader.h"
    #include "CalcViewModel/Common/LocalizationService.h"
    
    using namespace CalculatorApp::Common;
    using namespace CalculatorApp::Common::LocalizationServiceProperties;
    using namespace CalculatorApp::DataLoaders;
    using namespace CalculatorApp::ViewModel;
    using namespace CalculatorUnitTests;
    using namespace Concurrency;
    using namespace Platform;
    using namespace std;
    using namespace UnitConversionManager;
    using namespace Windows::Foundation;
    using namespace Windows::Storage;
    using namespace Windows::Web::Http;
    using namespace Microsoft::VisualStudio::CppUnitTestFramework;
    
    namespace CalculatorApp
    {
        namespace DataLoaders
        {
            class MockCurrencyHttpClientWithResult : public CurrencyHttpClient
            {
            public:
                MockCurrencyHttpClientWithResult(String^ staticResponse, String^ allRatiosResponse) :
                    m_staticResponse(staticResponse),
                    m_allRatiosResponse(allRatiosResponse)
                {
                }
    
                IAsyncOperationWithProgress<String^, HttpProgress>^ GetCurrencyMetadata() override
                {
                    return ref new MockAsyncOperationWithProgress(m_staticResponse);
                }
    
                IAsyncOperationWithProgress<String^, HttpProgress>^ GetCurrencyRatios() override
                {
                    return ref new MockAsyncOperationWithProgress(m_allRatiosResponse);
                }
    
            private:
                String^ m_staticResponse;
                String^ m_allRatiosResponse;
            };
    
            class MockCurrencyHttpClientThrowsException : public CurrencyHttpClient
            {
            public:
                MockCurrencyHttpClientThrowsException() {}
    
                IAsyncOperationWithProgress<String^, HttpProgress>^ GetCurrencyMetadata() override
                {
                    throw ref new NotImplementedException();
                }
    
                IAsyncOperationWithProgress<String^, HttpProgress>^ GetCurrencyRatios() override
                {
                    throw ref new NotImplementedException();
                }
            };
        }
    }
    
    class DataLoadedCallback : public UnitConversionManager::IViewModelCurrencyCallback
    {
    public:
        DataLoadedCallback(task_completion_event<void> tce) :
            m_task_completion_event{ tce }
        {}
    
        void CurrencyDataLoadFinished(bool /*didLoad*/) override
        {
            m_task_completion_event.set();
        }
    
        void CurrencySymbolsCallback(_In_ const wstring& /*fromSymbol*/, _In_ const wstring& /*toSymbol*/) override {}
        void CurrencyRatiosCallback(_In_ const wstring& /*ratioEquality*/, _In_ const wstring& /*accRatioEquality*/) override {}
        void CurrencyTimestampCallback(_In_ const std::wstring& /*timestamp*/, bool /*isWeekOldData*/) override {}
        void NetworkBehaviorChanged(_In_ int /*newBehavior*/) override {}
    
    private:
        Concurrency::task_completion_event<void> m_task_completion_event;
    };
    
    namespace CalculatorUnitTests
    {
        constexpr auto sc_Language_EN = L"en-US";
    
        const UCM::Category CURRENCY_CATEGORY = { NavCategory::Serialize(ViewMode::Currency), L"Currency", false /*supportsNegative*/ };
    
        unique_ptr<CurrencyDataLoader> MakeLoaderWithResults(String^ staticResponse, String^ allRatiosResponse)
        {
            auto client = make_unique<MockCurrencyHttpClientWithResult>(staticResponse, allRatiosResponse);
            client->SetSourceCurrencyCode(StringReference(DefaultCurrencyCode.data()));
            return make_unique<CurrencyDataLoader>(move(client));
        }
    
        String^ SerializeContent(const vector<String^>& data)
        {
            String^ result = L"";
            String^ delimiter = CurrencyDataLoaderConstants::CacheDelimiter;
            for (String^ content : data)
            {
                result += (delimiter + content);
            }
    
            return result;
        }
    
        bool WriteToFileInLocalCacheFolder(String^ filename, String^ content)
        {
            try
            {
                StorageFolder^ localFolder = ApplicationData::Current->LocalCacheFolder;
                StorageFile^ file = create_task(localFolder->CreateFileAsync(filename, CreationCollisionOption::ReplaceExisting)).get();
                create_task(FileIO::WriteTextAsync(file, content)).wait();
                return true;
            }
            catch (Exception^ ex)
            {
                return false;
            }
        }
    
        bool DeleteFileFromLocalCacheFolder(String^ filename)
        {
            try
            {
                StorageFolder^ folder = ApplicationData::Current->LocalCacheFolder;
                IAsyncOperation<StorageFile^>^ fileOperation = folder->GetFileAsync(filename);
                StorageFile^ file = create_task(fileOperation).get();
                create_task(file->DeleteAsync()).get();
                return true;
            }
            catch (Platform::Exception^ ex)
            {
                // FileNotFoundException is a valid result
                return ex->HResult == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
            }
            catch (...)
            {
                return false;
            }
        }
    
        bool DeleteCurrencyCacheFiles()
        {
            try
            {
                bool deletedStaticData = DeleteFileFromLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename);
                bool deletedAllRatiosData = DeleteFileFromLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename);
    
                return deletedStaticData && deletedAllRatiosData;
            }
            catch (...)
            {
                return false;
            }
        }
    
        void InsertToLocalSettings(String^ key, Object^ value)
        {
            ApplicationData::Current->LocalSettings->Values->Insert(key, value);
        }
    
        void RemoveFromLocalSettings(String^ key)
        {
            // Safe to call, even if the key does not exist.
            ApplicationData::Current->LocalSettings->Values->Remove(key);
        }
    
        void StandardCacheSetup()
        {
            // Insert current time so data is less than a day old.
            DateTime now = Utils::GetUniversalSystemTime();
            InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, now);
            InsertToLocalSettings(CurrencyDataLoaderConstants::CacheLangcodeKey, StringReference(sc_Language_EN));
    
            VERIFY_IS_TRUE(DeleteCurrencyCacheFiles());
    
            VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename, CurrencyHttpClient::GetRawStaticDataResponse()));
            VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename, CurrencyHttpClient::GetRawAllRatiosDataResponse()));
        }
    
        TEST_CLASS(CurrencyConverterLoadTests)
        {
        public:
            TEST_METHOD_INITIALIZE(DeleteCacheFiles)
            {
                DeleteCurrencyCacheFiles();
            }
    
            TEST_METHOD(LoadFromCache_Fail_NoCacheKey)
            {
                RemoveFromLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey);
    
                CurrencyDataLoader loader{ nullptr };
    
                bool didLoad = loader.TryLoadDataFromCacheAsync().get();
    
                VERIFY_IS_FALSE(didLoad);
                VERIFY_IS_FALSE(loader.LoadFinished());
                VERIFY_IS_FALSE(loader.LoadedFromCache());
            }
    
            TEST_METHOD(LoadFromCache_Fail_OlderThanADay)
            {
                // Insert 24 hours ago so data is considered stale.
                // This will cause the load from cache to fail.
                DateTime now = Utils::GetUniversalSystemTime();
                DateTime dayOld;
                dayOld.UniversalTime = now.UniversalTime - CurrencyDataLoaderConstants::DayDuration - 1;
                InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, dayOld);
    
                CurrencyDataLoader loader{ nullptr };
    
                bool didLoad = loader.TryLoadDataFromCacheAsync().get();
    
                VERIFY_IS_FALSE(didLoad);
                VERIFY_IS_FALSE(loader.LoadFinished());
                VERIFY_IS_FALSE(loader.LoadedFromCache());
            }
    
            TEST_METHOD(LoadFromCache_Fail_StaticDataFileDoesNotExist)
            {
                // Insert current time so data is less than a day old.
                // This will cause the load to continue to attempt to load the file.
                DateTime now = Utils::GetUniversalSystemTime();
                InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, now);
    
                VERIFY_IS_TRUE(DeleteFileFromLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename));
                VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename, CurrencyHttpClient::GetRawAllRatiosDataResponse()));
    
                CurrencyDataLoader loader{ nullptr };
    
                bool didLoad = loader.TryLoadDataFromCacheAsync().get();
    
                VERIFY_IS_FALSE(didLoad);
                VERIFY_IS_FALSE(loader.LoadFinished());
                VERIFY_IS_FALSE(loader.LoadedFromCache());
            }
    
            TEST_METHOD(LoadFromCache_Fail_AllRatiosDataFileDoesNotExist)
            {
                // Insert current time so data is less than a day old.
                // This will cause the load to continue to attempt to load the file.
                DateTime now = Utils::GetUniversalSystemTime();
                InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, now);
    
                VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename, CurrencyHttpClient::GetRawStaticDataResponse()));
                VERIFY_IS_TRUE(DeleteFileFromLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename));
    
                CurrencyDataLoader loader{ nullptr };
    
                bool didLoad = loader.TryLoadDataFromCacheAsync().get();
    
                VERIFY_IS_FALSE(didLoad);
                VERIFY_IS_FALSE(loader.LoadFinished());
                VERIFY_IS_FALSE(loader.LoadedFromCache());
            }
    
            TEST_METHOD(LoadFromCache_Fail_ResponseLanguageChanged)
            {
                DateTime now = Utils::GetUniversalSystemTime();
                InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, now);
    
                // Tests always use en-US as response language. Insert a different lang-code to fail the test.
                InsertToLocalSettings(CurrencyDataLoaderConstants::CacheLangcodeKey, L"ar-SA");
    
                VERIFY_IS_TRUE(WriteToFileInLocalCacheFolder(CurrencyDataLoaderConstants::StaticDataFilename, CurrencyHttpClient::GetRawStaticDataResponse()));
                VERIFY_IS_TRUE(DeleteFileFromLocalCacheFolder(CurrencyDataLoaderConstants::AllRatiosDataFilename));
    
                CurrencyDataLoader loader{ nullptr };
    
                bool didLoad = loader.TryLoadDataFromCacheAsync().get();
    
                VERIFY_IS_FALSE(didLoad);
                VERIFY_IS_FALSE(loader.LoadFinished());
                VERIFY_IS_FALSE(loader.LoadedFromCache());
            }
    
            TEST_METHOD(LoadFromCache_Success)
            {
                StandardCacheSetup();
    
                CurrencyDataLoader loader{ nullptr };
    
                bool didLoad = loader.TryLoadDataFromCacheAsync().get();
    
                VERIFY_IS_TRUE(didLoad);
                VERIFY_IS_TRUE(loader.LoadFinished());
                VERIFY_IS_TRUE(loader.LoadedFromCache());
            }
    
            TEST_METHOD(LoadFromWeb_Fail_ClientIsNullptr)
            {
                CurrencyDataLoader loader{ nullptr };
    
                bool didLoad = loader.TryLoadDataFromWebAsync().get();
    
                VERIFY_IS_FALSE(didLoad);
                VERIFY_IS_FALSE(loader.LoadFinished());
                VERIFY_IS_FALSE(loader.LoadedFromWeb());
            }
    
            TEST_METHOD(LoadFromWeb_Fail_WebException)
            {
                CurrencyDataLoader loader{ make_unique<MockCurrencyHttpClientThrowsException>() };
    
                bool didLoad = loader.TryLoadDataFromWebAsync().get();
    
                VERIFY_IS_FALSE(didLoad);
                VERIFY_IS_FALSE(loader.LoadFinished());
                VERIFY_IS_FALSE(loader.LoadedFromWeb());
            }
    
            TEST_METHOD(LoadFromWeb_Success)
            {
                String^ staticResponse = CurrencyHttpClient::GetRawStaticDataResponse();
                String^ allRatiosResponse = CurrencyHttpClient::GetRawAllRatiosDataResponse();
                unique_ptr<CurrencyDataLoader> loader = MakeLoaderWithResults(staticResponse, allRatiosResponse);
    
                bool didLoad = loader->TryLoadDataFromWebAsync().get();
    
                VERIFY_IS_TRUE(didLoad);
                VERIFY_IS_TRUE(loader->LoadFinished());
                VERIFY_IS_TRUE(loader->LoadedFromWeb());
            }
    
            TEST_METHOD(Load_Success_LoadedFromCache)
            {
                StandardCacheSetup();
    
                CurrencyDataLoader loader{ nullptr };
    
                auto data_loaded_event = task_completion_event<void>();
                loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
    
                auto data_loaded_task = create_task(data_loaded_event);
                loader.LoadData();
                data_loaded_task.wait();
    
                VERIFY_IS_TRUE(loader.LoadFinished());
                VERIFY_IS_TRUE(loader.LoadedFromCache());
                VERIFY_IS_FALSE(loader.LoadedFromWeb());
            }
    
            TEST_METHOD(Load_Success_LoadedFromWeb)
            {
                // Insert 24 hours ago so data is considered stale.
                // This will cause the load from cache to fail.
                DateTime now = Utils::GetUniversalSystemTime();
                DateTime dayOld;
                dayOld.UniversalTime = now.UniversalTime - CurrencyDataLoaderConstants::DayDuration - 1;
                InsertToLocalSettings(CurrencyDataLoaderConstants::CacheTimestampKey, dayOld);
    
                String^ staticResponse = CurrencyHttpClient::GetRawStaticDataResponse();
                String^ allRatiosResponse = CurrencyHttpClient::GetRawAllRatiosDataResponse();
                unique_ptr<CurrencyDataLoader> loader = MakeLoaderWithResults(staticResponse, allRatiosResponse);
    
                auto data_loaded_event = task_completion_event<void>();
                loader->SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
    
                auto data_loaded_task = create_task(data_loaded_event);
                loader->LoadData();
                data_loaded_task.wait();
    
                VERIFY_IS_TRUE(loader->LoadFinished());
                VERIFY_IS_FALSE(loader->LoadedFromCache());
                VERIFY_IS_TRUE(loader->LoadedFromWeb());
            }
        };
    
        TEST_CLASS(CurrencyConverterUnitTests)
        {
            const UCM::Unit GetUnit(const vector<UCM::Unit>& unitList, const wstring& target)
            {
                return *find_if(begin(unitList), end(unitList), [&target](const UCM::Unit& u) { return u.abbreviation == target; });
            }
    
            TEST_METHOD(Loaded_LoadOrderedUnits)
            {
                StandardCacheSetup();
    
                CurrencyDataLoader loader{ nullptr };
    
                auto data_loaded_event = task_completion_event<void>();
                loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
    
                auto data_loaded_task = create_task(data_loaded_event);
                loader.LoadData();
                data_loaded_task.wait();
    
                VERIFY_IS_TRUE(loader.LoadFinished());
                VERIFY_IS_TRUE(loader.LoadedFromCache());
                VERIFY_IS_FALSE(loader.LoadedFromWeb());
    
                vector<UCM::Unit> unitList = loader.LoadOrderedUnits(CURRENCY_CATEGORY);
                VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
    
                const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
                const UCM::Unit eurUnit = GetUnit(unitList, L"EUR");
    
                VERIFY_ARE_EQUAL(wstring(L"United States - Dollar"), usdUnit.name);
                VERIFY_ARE_EQUAL(wstring(L"USD"), usdUnit.abbreviation);
    
                VERIFY_ARE_EQUAL(wstring(L"Europe - Euro"), eurUnit.name);
                VERIFY_ARE_EQUAL(wstring(L"EUR"), eurUnit.abbreviation);
            }
    
            TEST_METHOD(Loaded_LoadOrderedRatios)
            {
                StandardCacheSetup();
    
                CurrencyDataLoader loader{ nullptr };
    
                auto data_loaded_event = task_completion_event<void>();
                loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
    
                auto data_loaded_task = create_task(data_loaded_event);
                loader.LoadData();
                data_loaded_task.wait();
    
                VERIFY_IS_TRUE(loader.LoadFinished());
                VERIFY_IS_TRUE(loader.LoadedFromCache());
                VERIFY_IS_FALSE(loader.LoadedFromWeb());
    
                vector<UCM::Unit> unitList = loader.LoadOrderedUnits(CURRENCY_CATEGORY);
                VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
    
                const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
                const UCM::Unit eurUnit = GetUnit(unitList, L"EUR");
    
                unordered_map<UCM::Unit, UCM::ConversionData, UCM::UnitHash> ratios = loader.LoadOrderedRatios(usdUnit);
                VERIFY_ARE_EQUAL(size_t{ 2 }, ratios.size());
    
                UCM::ConversionData usdRatioData = ratios[usdUnit];
                VERIFY_IS_TRUE((std::abs(1.0 - usdRatioData.ratio) < 1e-1));
    
                UCM::ConversionData eurRatioData = ratios[eurUnit];
                VERIFY_IS_TRUE((std::abs(0.920503 - eurRatioData.ratio) < 1e-6));
            }
    
            TEST_METHOD(Loaded_GetCurrencySymbols_Valid)
            {
                StandardCacheSetup();
    
                CurrencyDataLoader loader{ nullptr };
    
                auto data_loaded_event = task_completion_event<void>();
                loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
    
                auto data_loaded_task = create_task(data_loaded_event);
                loader.LoadData();
                data_loaded_task.wait();
    
                VERIFY_IS_TRUE(loader.LoadFinished());
                VERIFY_IS_TRUE(loader.LoadedFromCache());
                VERIFY_IS_FALSE(loader.LoadedFromWeb());
    
                vector<UCM::Unit> unitList = loader.LoadOrderedUnits(CURRENCY_CATEGORY);
                VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
    
                const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
                const UCM::Unit eurUnit = GetUnit(unitList, L"EUR");
    
                const pair<wstring, wstring> symbols = loader.GetCurrencySymbols(usdUnit, eurUnit);
    
                VERIFY_ARE_EQUAL(wstring(L"$"), symbols.first);
                VERIFY_ARE_EQUAL(wstring(L"\x20ac"), symbols.second); // €
            }
    
            TEST_METHOD(Loaded_GetCurrencySymbols_Invalid)
            {
                StandardCacheSetup();
    
                CurrencyDataLoader loader{ nullptr };
    
                auto data_loaded_event = task_completion_event<void>();
                loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
    
                auto data_loaded_task = create_task(data_loaded_event);
                loader.LoadData();
                data_loaded_task.wait();
    
                VERIFY_IS_TRUE(loader.LoadFinished());
                VERIFY_IS_TRUE(loader.LoadedFromCache());
                VERIFY_IS_FALSE(loader.LoadedFromWeb());
    
                const UCM::Unit fakeUnit1 = {
                    1, L"fakeUnit1", L"FUD1", false, false, false
                };
    
                const UCM::Unit fakeUnit2 = {
                    2, L"fakeUnit2", L"FUD2", false, false, false
                };
    
                pair<wstring, wstring> symbols = loader.GetCurrencySymbols(fakeUnit1, fakeUnit2);
    
                VERIFY_ARE_EQUAL(wstring(L""), wstring(symbols.first.c_str()));
                VERIFY_ARE_EQUAL(wstring(L""), wstring(symbols.second.c_str()));
    
                // Verify that when only one unit is valid, both symbols return as empty string.
                vector<UCM::Unit> unitList = loader.LoadOrderedUnits(CURRENCY_CATEGORY);
                VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
    
                const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
    
                symbols = loader.GetCurrencySymbols(fakeUnit1, usdUnit);
    
                VERIFY_ARE_EQUAL(wstring(L""), symbols.first);
                VERIFY_ARE_EQUAL(wstring(L""), symbols.second);
    
                symbols = loader.GetCurrencySymbols(usdUnit, fakeUnit1);
    
                VERIFY_ARE_EQUAL(wstring(L""), symbols.first);
                VERIFY_ARE_EQUAL(wstring(L""), symbols.second);
            }
    
            TEST_METHOD(Loaded_GetCurrencyRatioEquality_Valid)
            {
                StandardCacheSetup();
    
                CurrencyDataLoader loader{ nullptr };
    
                auto data_loaded_event = task_completion_event<void>();
                loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
    
                auto data_loaded_task = create_task(data_loaded_event);
                loader.LoadData();
                data_loaded_task.wait();
    
                VERIFY_IS_TRUE(loader.LoadFinished());
                VERIFY_IS_TRUE(loader.LoadedFromCache());
                VERIFY_IS_FALSE(loader.LoadedFromWeb());
    
                vector<UCM::Unit> unitList = loader.LoadOrderedUnits(CURRENCY_CATEGORY);
                VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
    
                const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
                const UCM::Unit eurUnit = GetUnit(unitList, L"EUR");
    
                const pair<wstring, wstring> ratio = loader.GetCurrencyRatioEquality(usdUnit, eurUnit);
    
                VERIFY_ARE_EQUAL(wstring(L"1 USD = 0.9205 EUR"), ratio.first);
                VERIFY_ARE_EQUAL(wstring(L"1 United States Dollar = 0.9205 Europe Euro"), ratio.second);
            }
    
            TEST_METHOD(Loaded_GetCurrencyRatioEquality_Invalid)
            {
                StandardCacheSetup();
    
                CurrencyDataLoader loader{ nullptr };
    
                auto data_loaded_event = task_completion_event<void>();
                loader.SetViewModelCallback(make_shared<DataLoadedCallback>(data_loaded_event));
    
                auto data_loaded_task = create_task(data_loaded_event);
                loader.LoadData();
                data_loaded_task.wait();
    
                VERIFY_IS_TRUE(loader.LoadFinished());
                VERIFY_IS_TRUE(loader.LoadedFromCache());
                VERIFY_IS_FALSE(loader.LoadedFromWeb());
    
                const UCM::Unit fakeUnit1 = {
                    1, L"fakeUnit1", L"fakeCountry1", L"FUD1", false, false, false
                };
                const UCM::Unit fakeUnit2 = {
                    2, L"fakeUnit2", L"fakeCountry2", L"FUD2", false, false, false
                };
    
                pair<wstring, wstring> ratio = loader.GetCurrencyRatioEquality(fakeUnit1, fakeUnit2);
    
                VERIFY_ARE_EQUAL(wstring(L""), ratio.first);
                VERIFY_ARE_EQUAL(wstring(L""), ratio.second);
    
                // Verify that when only one unit is valid, both symbols return as empty string.
                vector<UCM::Unit> unitList = loader.LoadOrderedUnits(CURRENCY_CATEGORY);
                VERIFY_ARE_EQUAL(size_t{ 2 }, unitList.size());
    
                const UCM::Unit usdUnit = GetUnit(unitList, L"USD");
    
                ratio = loader.GetCurrencyRatioEquality(fakeUnit1, usdUnit);
    
                VERIFY_ARE_EQUAL(wstring(L""), ratio.first);
                VERIFY_ARE_EQUAL(wstring(L""), ratio.second);
    
                ratio = loader.GetCurrencyRatioEquality(usdUnit, fakeUnit1);
    
                VERIFY_ARE_EQUAL(wstring(L""), ratio.first);
                VERIFY_ARE_EQUAL(wstring(L""), ratio.second);
            }
        };
    }

    여기서 무엇이 깨진 문자열인지를 못 찾겠네요. 아시는 분들 조언 좀 부탁드립니다...


    추신 > 빌드 문제는 unitest  서브 프로젝트를 솔루션에서 제거하고 났더니 문제없이 빌드 및 실행이 가능하더군요. 
    • 편집됨 ohseihyung 2019년 4월 4일 목요일 오전 9:02
    2019년 4월 4일 목요일 오전 7:42
  • 아래의 글을 참고해서 수정하시면 됩니다.

    Visual C++ 컴파일 오류 - error C2220: warning treated as error - no 'object' file generated
    ; http://www.sysnet.pe.kr/2/0/11860

    • 답변으로 표시됨 ohseihyung 2019년 4월 5일 금요일 오전 10:42
    2019년 4월 5일 금요일 오전 3:25
  • 답변 감사드립니다.

    덕분에 문제 해결했습니다.

    2019년 4월 5일 금요일 오전 10:41