mirror of
https://github.com/chromium/crashpad.git
synced 2025-01-14 01:08:01 +08:00
Add mac_util, including MacOSXMinorVersion(), MacOSXVersion(), and
MacModelAndBoard(), along with their tests. TEST=util_test MacUtil.* R=rsesek@chromium.org Review URL: https://codereview.chromium.org/473023002
This commit is contained in:
parent
a70edb3b7f
commit
8fe32b7b9c
282
util/mac/mac_util.cc
Normal file
282
util/mac/mac_util.cc
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// 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 "util/mac/mac_util.h"
|
||||||
|
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
#include <IOKit/IOKitLib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
|
#include "base/logging.h"
|
||||||
|
#include "base/mac/foundation_util.h"
|
||||||
|
#include "base/mac/scoped_cftyperef.h"
|
||||||
|
#include "base/mac/scoped_ioobject.h"
|
||||||
|
#include "base/strings/string_number_conversions.h"
|
||||||
|
#include "base/strings/string_piece.h"
|
||||||
|
#include "base/strings/stringprintf.h"
|
||||||
|
#include "base/strings/sys_string_conversions.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
// Private CoreFoundation internals. See 10.9.2 CF-855.14/CFPriv.h and
|
||||||
|
// CF-855.14/CFUtilities.c. These are marked for weak import because they’re
|
||||||
|
// private and subject to change.
|
||||||
|
|
||||||
|
#define WEAK_IMPORT __attribute__((weak_import))
|
||||||
|
|
||||||
|
// Don’t call these functions directly, call them through the
|
||||||
|
// TryCFCopy*VersionDictionary() helpers to account for the possibility that
|
||||||
|
// they may not be present at runtime.
|
||||||
|
CFDictionaryRef _CFCopySystemVersionDictionary() WEAK_IMPORT;
|
||||||
|
CFDictionaryRef _CFCopyServerVersionDictionary() WEAK_IMPORT;
|
||||||
|
|
||||||
|
// Don’t use these constants with CFDictionaryGetValue() directly, use them with
|
||||||
|
// the TryCFDictionaryGetValue() wrapper to account for the possibility that
|
||||||
|
// they may not be present at runtime.
|
||||||
|
extern const CFStringRef _kCFSystemVersionProductNameKey WEAK_IMPORT;
|
||||||
|
extern const CFStringRef _kCFSystemVersionProductVersionKey WEAK_IMPORT;
|
||||||
|
extern const CFStringRef _kCFSystemVersionProductVersionExtraKey WEAK_IMPORT;
|
||||||
|
extern const CFStringRef _kCFSystemVersionBuildVersionKey WEAK_IMPORT;
|
||||||
|
|
||||||
|
#undef WEAK_IMPORT
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Returns the running system’s Darwin major version. Don’t call this, it’s an
|
||||||
|
// implementation detail and its result is meant to be cached by
|
||||||
|
// MacOSXMinorVersion().
|
||||||
|
//
|
||||||
|
// This is very similar to Chromium’s base/mac/mac_util.mm
|
||||||
|
// DarwinMajorVersionInternal().
|
||||||
|
int DarwinMajorVersion() {
|
||||||
|
// base::OperatingSystemVersionNumbers calls Gestalt(), which is a
|
||||||
|
// higher-level function than is needed. It might perform unnecessary
|
||||||
|
// operations. On 10.6, it was observed to be able to spawn threads (see
|
||||||
|
// http://crbug.com/53200). It might also read files or perform other blocking
|
||||||
|
// operations. Actually, nobody really knows for sure just what Gestalt()
|
||||||
|
// might do, or what it might be taught to do in the future.
|
||||||
|
//
|
||||||
|
// uname(), on the other hand, is implemented as a simple series of sysctl()
|
||||||
|
// system calls to obtain the relevant data from the kernel. The data is
|
||||||
|
// compiled right into the kernel, so no threads or blocking or other funny
|
||||||
|
// business is necessary.
|
||||||
|
|
||||||
|
utsname uname_info;
|
||||||
|
int rv = uname(&uname_info);
|
||||||
|
PCHECK(rv == 0) << "uname";
|
||||||
|
|
||||||
|
DCHECK_EQ(strcmp(uname_info.sysname, "Darwin"), 0) << "unexpected sysname "
|
||||||
|
<< uname_info.sysname;
|
||||||
|
|
||||||
|
char* dot = strchr(uname_info.release, '.');
|
||||||
|
CHECK(dot);
|
||||||
|
|
||||||
|
int darwin_major_version = 0;
|
||||||
|
CHECK(base::StringToInt(
|
||||||
|
base::StringPiece(uname_info.release, dot - uname_info.release),
|
||||||
|
&darwin_major_version));
|
||||||
|
|
||||||
|
return darwin_major_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpers for the weak-imported private CoreFoundation internals.
|
||||||
|
|
||||||
|
CFDictionaryRef TryCFCopySystemVersionDictionary() {
|
||||||
|
if (_CFCopySystemVersionDictionary) {
|
||||||
|
return _CFCopySystemVersionDictionary();
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFDictionaryRef TryCFCopyServerVersionDictionary() {
|
||||||
|
if (_CFCopyServerVersionDictionary) {
|
||||||
|
return _CFCopyServerVersionDictionary();
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void* TryCFDictionaryGetValue(CFDictionaryRef dictionary,
|
||||||
|
const void* value) {
|
||||||
|
if (value) {
|
||||||
|
return CFDictionaryGetValue(dictionary, value);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts |version| to a triplet of version numbers on behalf of
|
||||||
|
// MacOSXVersion(). Returns true on success. If |version| does not have the
|
||||||
|
// expected format, returns false. |version| must be in the form "10.9.2" or
|
||||||
|
// just "10.9". In the latter case, |bugfix| will be set to 0.
|
||||||
|
bool StringToVersionNumbers(const std::string& version,
|
||||||
|
int* major,
|
||||||
|
int* minor,
|
||||||
|
int* bugfix) {
|
||||||
|
size_t first_dot = version.find_first_of('.');
|
||||||
|
if (first_dot == 0 || first_dot == std::string::npos ||
|
||||||
|
first_dot == version.length() - 1) {
|
||||||
|
LOG(ERROR) << "version has unexpected format";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!base::StringToInt(base::StringPiece(&version[0], first_dot), major)) {
|
||||||
|
LOG(ERROR) << "version has unexpected format";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t second_dot = version.find_first_of('.', first_dot + 1);
|
||||||
|
if (second_dot == version.length() - 1) {
|
||||||
|
LOG(ERROR) << "version has unexpected format";
|
||||||
|
return false;
|
||||||
|
} else if (second_dot == std::string::npos) {
|
||||||
|
second_dot = version.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!base::StringToInt(base::StringPiece(&version[first_dot + 1],
|
||||||
|
second_dot - first_dot - 1),
|
||||||
|
minor)) {
|
||||||
|
LOG(ERROR) << "version has unexpected format";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (second_dot == version.length()) {
|
||||||
|
*bugfix = 0;
|
||||||
|
} else if (!base::StringToInt(
|
||||||
|
base::StringPiece(&version[second_dot + 1],
|
||||||
|
version.length() - second_dot - 1),
|
||||||
|
bugfix)) {
|
||||||
|
LOG(ERROR) << "version has unexpected format";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string IORegistryEntryDataPropertyAsString(io_registry_entry_t entry,
|
||||||
|
CFStringRef key) {
|
||||||
|
base::ScopedCFTypeRef<CFTypeRef> property(
|
||||||
|
IORegistryEntryCreateCFProperty(entry, key, kCFAllocatorDefault, 0));
|
||||||
|
CFDataRef data = base::mac::CFCast<CFDataRef>(property);
|
||||||
|
if (data && CFDataGetLength(data) > 0) {
|
||||||
|
return reinterpret_cast<const char*>(CFDataGetBytePtr(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
int MacOSXMinorVersion() {
|
||||||
|
// The Darwin major version is always 4 greater than the Mac OS X minor
|
||||||
|
// version for Darwin versions beginning with 6, corresponding to Mac OS X
|
||||||
|
// 10.2.
|
||||||
|
static int mac_os_x_minor_version = DarwinMajorVersion() - 4;
|
||||||
|
DCHECK(mac_os_x_minor_version >= 2);
|
||||||
|
return mac_os_x_minor_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacOSXVersion(int* major,
|
||||||
|
int* minor,
|
||||||
|
int* bugfix,
|
||||||
|
std::string* build,
|
||||||
|
bool* server,
|
||||||
|
std::string* version_string) {
|
||||||
|
base::ScopedCFTypeRef<CFDictionaryRef> dictionary(
|
||||||
|
TryCFCopyServerVersionDictionary());
|
||||||
|
if (dictionary) {
|
||||||
|
*server = true;
|
||||||
|
} else {
|
||||||
|
dictionary.reset(TryCFCopySystemVersionDictionary());
|
||||||
|
if (!dictionary) {
|
||||||
|
LOG(ERROR) << "_CFCopySystemVersionDictionary failed";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*server = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
|
CFStringRef version_cf = base::mac::CFCast<CFStringRef>(
|
||||||
|
TryCFDictionaryGetValue(dictionary, _kCFSystemVersionProductVersionKey));
|
||||||
|
std::string version;
|
||||||
|
if (!version_cf) {
|
||||||
|
LOG(ERROR) << "version_cf not found";
|
||||||
|
success = false;
|
||||||
|
} else {
|
||||||
|
version = base::SysCFStringRefToUTF8(version_cf);
|
||||||
|
success &= StringToVersionNumbers(version, major, minor, bugfix);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFStringRef build_cf = base::mac::CFCast<CFStringRef>(
|
||||||
|
TryCFDictionaryGetValue(dictionary, _kCFSystemVersionBuildVersionKey));
|
||||||
|
if (!build_cf) {
|
||||||
|
LOG(ERROR) << "build_cf not found";
|
||||||
|
success = false;
|
||||||
|
} else {
|
||||||
|
build->assign(base::SysCFStringRefToUTF8(build_cf));
|
||||||
|
}
|
||||||
|
|
||||||
|
CFStringRef product_cf = base::mac::CFCast<CFStringRef>(
|
||||||
|
TryCFDictionaryGetValue(dictionary, _kCFSystemVersionProductNameKey));
|
||||||
|
std::string product;
|
||||||
|
if (!product_cf) {
|
||||||
|
LOG(ERROR) << "product_cf not found";
|
||||||
|
success = false;
|
||||||
|
} else {
|
||||||
|
product = base::SysCFStringRefToUTF8(product_cf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This key is not required, and in fact is normally not present.
|
||||||
|
CFStringRef extra_cf = base::mac::CFCast<CFStringRef>(TryCFDictionaryGetValue(
|
||||||
|
dictionary, _kCFSystemVersionProductVersionExtraKey));
|
||||||
|
std::string extra;
|
||||||
|
if (extra_cf) {
|
||||||
|
extra = base::SysCFStringRefToUTF8(extra_cf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!product.empty() || !version.empty() || !build->empty()) {
|
||||||
|
if (!extra.empty()) {
|
||||||
|
version_string->assign(base::StringPrintf("%s %s %s (%s)",
|
||||||
|
product.c_str(),
|
||||||
|
version.c_str(),
|
||||||
|
extra.c_str(),
|
||||||
|
build->c_str()));
|
||||||
|
} else {
|
||||||
|
version_string->assign(base::StringPrintf(
|
||||||
|
"%s %s (%s)", product.c_str(), version.c_str(), build->c_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacModelAndBoard(std::string* model, std::string* board_id) {
|
||||||
|
base::mac::ScopedIOObject<io_service_t> platform_expert(
|
||||||
|
IOServiceGetMatchingService(kIOMasterPortDefault,
|
||||||
|
IOServiceMatching("IOPlatformExpertDevice")));
|
||||||
|
if (platform_expert) {
|
||||||
|
model->assign(
|
||||||
|
IORegistryEntryDataPropertyAsString(platform_expert, CFSTR("model")));
|
||||||
|
board_id->assign(IORegistryEntryDataPropertyAsString(platform_expert,
|
||||||
|
CFSTR("board-id")));
|
||||||
|
} else {
|
||||||
|
model->clear();
|
||||||
|
board_id->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace crashpad
|
73
util/mac/mac_util.h
Normal file
73
util/mac/mac_util.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef CRASHPAD_UTIL_MAC_MAC_UTIL_H_
|
||||||
|
#define CRASHPAD_UTIL_MAC_MAC_UTIL_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
//! \brief Returns the version of the running operating system.
|
||||||
|
//!
|
||||||
|
//! \return The minor version of the operating system, such as `9` for Mac OS X
|
||||||
|
//! 10.9.2.
|
||||||
|
//!
|
||||||
|
//! \note This is similar to the base::mac::IsOS*() family of functions, but
|
||||||
|
//! is provided for situations where the caller needs to obtain version
|
||||||
|
//! information beyond what is provided by Chromium’s base, or for when the
|
||||||
|
//! caller needs the actual minor version value.
|
||||||
|
int MacOSXMinorVersion();
|
||||||
|
|
||||||
|
//! \brief Returns the version of the running operating system.
|
||||||
|
//!
|
||||||
|
//! All parameters are required. No parameter may be `NULL`.
|
||||||
|
//!
|
||||||
|
//! \param[out] major The major version of the operating system, such as `10`
|
||||||
|
//! for Mac OS X 10.9.2.
|
||||||
|
//! \param[out] minor The major version of the operating system, such as `9` for
|
||||||
|
//! Mac OS X 10.9.2.
|
||||||
|
//! \param[out] bugfix The bugfix version of the operating system, such as `2`
|
||||||
|
//! for Mac OS X 10.9.2.
|
||||||
|
//! \param[out] build The operating system’s build string, such as "13C64" for
|
||||||
|
//! Mac OS X 10.9.2.
|
||||||
|
//! \param[out] server `true` for a Mac OS X Server installation, `false`
|
||||||
|
//! otherwise (for a desktop/laptop, client, or workstation system).
|
||||||
|
//! \param[out] version_string A string representing the full operating system
|
||||||
|
//! version, such as `"Mac OS X 10.9.2 (13C64)"`.
|
||||||
|
//!
|
||||||
|
//! \return `true` on success, `false` on failure, with an error message logged.
|
||||||
|
//! A failure is considered to have occurred if any element could not be
|
||||||
|
//! determined. When this happens, their values will be untouched, but other
|
||||||
|
//! values that could be determined will still be set properly.
|
||||||
|
bool MacOSXVersion(int* major,
|
||||||
|
int* minor,
|
||||||
|
int* bugfix,
|
||||||
|
std::string* build,
|
||||||
|
bool* server,
|
||||||
|
std::string* version_string);
|
||||||
|
|
||||||
|
//! \brief Returns the model name and board ID of the running system.
|
||||||
|
//!
|
||||||
|
//! \param[out] model The system’s model name. A mid-2012 15" MacBook Pro would
|
||||||
|
//! report “MacBookPro10,1”.
|
||||||
|
//! \param[out] board_id The system’s board ID. A mid-2012 15" MacBook Pro would
|
||||||
|
//! report “Mac-C3EC7CD22292981F”.
|
||||||
|
//!
|
||||||
|
//! If a value cannot be determined, its string is cleared.
|
||||||
|
void MacModelAndBoard(std::string* model, std::string* board_id);
|
||||||
|
|
||||||
|
} // namespace crashpad
|
||||||
|
|
||||||
|
#endif // CRASHPAD_UTIL_MAC_MAC_UTIL_H_
|
149
util/mac/mac_util_test.mm
Normal file
149
util/mac/mac_util_test.mm
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// 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 "util/mac/mac_util.h"
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "base/mac/scoped_nsobject.h"
|
||||||
|
#include "base/strings/stringprintf.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#ifdef __GLIBCXX__
|
||||||
|
// When C++ exceptions are disabled, libstdc++ from GCC 4.2 defines |try| and
|
||||||
|
// |catch| so as to allow exception-expecting C++ code to build properly when
|
||||||
|
// language support for exceptions is not present. These macros interfere with
|
||||||
|
// the use of |@try| and |@catch| in Objective-C files such as this one.
|
||||||
|
// Undefine these macros here, after everything has been #included, since there
|
||||||
|
// will be no C++ uses and only Objective-C uses from this point on.
|
||||||
|
#undef try
|
||||||
|
#undef catch
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace crashpad;
|
||||||
|
|
||||||
|
// Runs /usr/bin/sw_vers with a single argument, |argument|, and places the
|
||||||
|
// command’s standard output into |output| after stripping the trailing newline.
|
||||||
|
// Fatal gtest assertions report tool failures, which the caller should check
|
||||||
|
// for with testing::Test::HasFatalFailure().
|
||||||
|
void SwVers(NSString* argument, std::string* output) {
|
||||||
|
@autoreleasepool {
|
||||||
|
base::scoped_nsobject<NSPipe> pipe([[NSPipe alloc] init]);
|
||||||
|
base::scoped_nsobject<NSTask> task([[NSTask alloc] init]);
|
||||||
|
[task setStandardOutput:pipe];
|
||||||
|
[task setLaunchPath:@"/usr/bin/sw_vers"];
|
||||||
|
[task setArguments:@[ argument ]];
|
||||||
|
|
||||||
|
@try {
|
||||||
|
[task launch];
|
||||||
|
}
|
||||||
|
@catch (NSException* exception) {
|
||||||
|
FAIL() << [[exception name] UTF8String] << ": "
|
||||||
|
<< [[exception reason] UTF8String];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSData* data = [[pipe fileHandleForReading] readDataToEndOfFile];
|
||||||
|
[task waitUntilExit];
|
||||||
|
|
||||||
|
ASSERT_EQ(NSTaskTerminationReasonExit, [task terminationReason]);
|
||||||
|
ASSERT_EQ(EXIT_SUCCESS, [task terminationStatus]);
|
||||||
|
|
||||||
|
output->assign(reinterpret_cast<const char*>([data bytes]), [data length]);
|
||||||
|
|
||||||
|
EXPECT_EQ('\n', output->at(output->size() - 1));
|
||||||
|
output->resize(output->size() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MacUtil, MacOSXVersion) {
|
||||||
|
int major;
|
||||||
|
int minor;
|
||||||
|
int bugfix;
|
||||||
|
std::string build;
|
||||||
|
bool server;
|
||||||
|
std::string version_string;
|
||||||
|
ASSERT_TRUE(
|
||||||
|
MacOSXVersion(&major, &minor, &bugfix, &build, &server, &version_string));
|
||||||
|
|
||||||
|
std::string version;
|
||||||
|
if (bugfix) {
|
||||||
|
version = base::StringPrintf("%d.%d.%d", major, minor, bugfix);
|
||||||
|
} else {
|
||||||
|
// 10.x.0 releases report their version string as simply 10.x.
|
||||||
|
version = base::StringPrintf("%d.%d", major, minor);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string expected_product_version;
|
||||||
|
SwVers(@"-productVersion", &expected_product_version);
|
||||||
|
if (Test::HasFatalFailure()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(expected_product_version, version);
|
||||||
|
|
||||||
|
std::string expected_build_version;
|
||||||
|
SwVers(@"-buildVersion", &expected_build_version);
|
||||||
|
if (Test::HasFatalFailure()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(expected_build_version, build);
|
||||||
|
|
||||||
|
std::string expected_product_name;
|
||||||
|
SwVers(@"-productName", &expected_product_name);
|
||||||
|
if (Test::HasFatalFailure()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for a space after the product name in the complete version string.
|
||||||
|
expected_product_name += ' ';
|
||||||
|
EXPECT_EQ(0u, version_string.find(expected_product_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MacUtil, MacOSXMinorVersion) {
|
||||||
|
// Make sure that MacOSXMinorVersion() and MacOSXVersion() agree. The two have
|
||||||
|
// their own distinct implementations, and the latter was checked against
|
||||||
|
// sw_vers above.
|
||||||
|
int major;
|
||||||
|
int minor;
|
||||||
|
int bugfix;
|
||||||
|
std::string build;
|
||||||
|
bool server;
|
||||||
|
std::string version_string;
|
||||||
|
ASSERT_TRUE(
|
||||||
|
MacOSXVersion(&major, &minor, &bugfix, &build, &server, &version_string));
|
||||||
|
|
||||||
|
EXPECT_EQ(minor, MacOSXMinorVersion());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MacUtil, MacModelAndBoard) {
|
||||||
|
// There’s not much that can be done to test these, so just make sure they’re
|
||||||
|
// not empty. The model could be compared against the parsed output of
|
||||||
|
// “system_profiler SPHardwareDataType”, but the board doesn’t show up
|
||||||
|
// anywhere other than the I/O Registry, and that’s exactly how
|
||||||
|
// MacModelAndBoard() gets the data, so it wouldn’t be a very useful test.
|
||||||
|
std::string model;
|
||||||
|
std::string board;
|
||||||
|
MacModelAndBoard(&model, &board);
|
||||||
|
|
||||||
|
EXPECT_FALSE(model.empty());
|
||||||
|
EXPECT_FALSE(board.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
@ -34,6 +34,8 @@
|
|||||||
'file/string_file_writer.h',
|
'file/string_file_writer.h',
|
||||||
'mac/launchd.h',
|
'mac/launchd.h',
|
||||||
'mac/launchd.mm',
|
'mac/launchd.mm',
|
||||||
|
'mac/mac_util.cc',
|
||||||
|
'mac/mac_util.h',
|
||||||
'mac/service_management.cc',
|
'mac/service_management.cc',
|
||||||
'mac/service_management.h',
|
'mac/service_management.h',
|
||||||
'mach/task_memory.cc',
|
'mach/task_memory.cc',
|
||||||
@ -89,6 +91,7 @@
|
|||||||
'sources': [
|
'sources': [
|
||||||
'file/string_file_writer_test.cc',
|
'file/string_file_writer_test.cc',
|
||||||
'mac/launchd_test.mm',
|
'mac/launchd_test.mm',
|
||||||
|
'mac/mac_util_test.mm',
|
||||||
'mac/service_management_test.mm',
|
'mac/service_management_test.mm',
|
||||||
'mach/task_memory_test.cc',
|
'mach/task_memory_test.cc',
|
||||||
'misc/initialization_state_dcheck_test.cc',
|
'misc/initialization_state_dcheck_test.cc',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user